@rotorsoft/act 1.24.0 → 1.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/signals.ts","../src/act.ts","../src/internal/event-versions.ts","../src/internal/walk-streams.ts","../src/internal/audit.ts","../src/internal/autoclose-policy.ts","../src/internal/autoclose-window.ts","../src/internal/close-signal.ts","../src/internal/defer-signal.ts","../src/internal/autoclose-reaction.ts","../src/internal/build-classify.ts","../src/internal/config.ts","../src/internal/defer-config.ts","../src/internal/merge.ts","../src/internal/builder-utils.ts","../src/internal/circuit-breaker.ts","../src/internal/close-cycle.ts","../src/internal/correlate-cycle.ts","../src/internal/correlator.ts","../src/internal/drain-cycle.ts","../src/internal/defer-timer.ts","../src/internal/drain-ratio.ts","../src/internal/drain.ts","../src/internal/event-sourcing.ts","../src/internal/backoff.ts","../src/internal/tracing.ts","../src/internal/projection-fold.ts","../src/internal/reactions.ts","../src/internal/settle.ts","../src/builders/act-builder.ts","../src/builders/projection-builder.ts","../src/builders/slice-builder.ts","../src/builders/state-builder.ts","../src/csv.ts"],"sourcesContent":["import { disposeAndExit, log } from \"./ports.js\";\n\n// Resolve the logger lazily inside each handler — calling log() here at\n// module load would register the default ConsoleLogger before user code\n// can inject (port singletons are first-call-wins).\nprocess.once(\"SIGINT\", async (arg?: any) => {\n log().info(arg, \"SIGINT\");\n await disposeAndExit(\"EXIT\");\n});\nprocess.once(\"SIGTERM\", async (arg?: any) => {\n log().info(arg, \"SIGTERM\");\n await disposeAndExit(\"EXIT\");\n});\nprocess.once(\"uncaughtException\", async (arg?: any) => {\n log().error(arg, \"Uncaught Exception\");\n await disposeAndExit(\"ERROR\");\n});\nprocess.once(\"unhandledRejection\", async (arg?: any) => {\n log().error(arg, \"Unhandled Rejection\");\n await disposeAndExit(\"ERROR\");\n});\n","import EventEmitter from \"node:events\";\nimport {\n ALL_LANES,\n type AuditDeps,\n audit,\n bare_patch,\n build_drain,\n build_es,\n build_handle,\n build_handle_batch,\n CircuitBreaker,\n type CircuitBreakerOptions,\n type CircuitState,\n CorrelateCycle,\n classify_registry,\n close_correlation,\n DrainController,\n type DrainOps,\n default_correlator,\n type EsOps,\n type EventLaneSet,\n type Handle,\n type HandleBatch,\n type PatchFn,\n resolveCircuitBreakerConfig,\n resolveDrainConfig,\n resolveSettleConfig,\n run_close_cycle,\n SettleLoop,\n scan,\n walk_streams,\n} from \"./internal/index.js\";\n\n// Public re-exports: these appear in ActOptions / ActLifecycleEvents above.\nexport type { CircuitBreakerOptions, CircuitState } from \"./internal/index.js\";\n\nimport {\n cache,\n dispose,\n log,\n type Scoped,\n scoped,\n store,\n TOMBSTONE_EVENT,\n} from \"./ports.js\";\nimport type {\n Actor,\n AsOf,\n AuditCategory,\n AuditFinding,\n AuditOptions,\n BatchHandler,\n BlockedLease,\n CloseResult,\n CloseTarget,\n Committed,\n Correlator,\n DoOptions,\n Drain,\n DrainOptions,\n EventSink,\n EventSource,\n IAct,\n LaneConfig,\n Lease,\n LoadTarget,\n Logger,\n Query,\n Registry,\n ScanOptions,\n ScanResult,\n Schema,\n SchemaRegister,\n Schemas,\n SettleOptions,\n Snapshot,\n State,\n Store,\n StoreNotification,\n StreamFilter,\n StreamPosition,\n Target,\n} from \"./types/index.js\";\n\n/**\n * @category Orchestrator\n * @see Store\n *\n * Main orchestrator for event-sourced state machines and workflows.\n *\n * It manages the lifecycle of actions, reactions, and event streams, providing APIs for loading state, executing actions, querying events, and draining reactions.\n *\n * ## Usage\n *\n * ```typescript\n * const app = new Act(registry, 100);\n * await app.do(\"increment\", { stream: \"counter1\", actor }, { by: 1 });\n * const snapshot = await app.load(Counter, \"counter1\");\n * await app.drain();\n * ```\n *\n * - Register event listeners with `.on(\"committed\", ...)` and `.on(\"acked\", ...)` to react to lifecycle events.\n * - Use `.query()` to analyze event streams for analytics or debugging.\n *\n * @template TSchemaReg SchemaRegister for state\n * @template TEvents Schemas for events\n * @template TActions Schemas for actions\n * @template TStateMap Map of state names to state schemas\n * @template TActor Actor type extending base Actor\n */\n/**\n * Default LRU cap for the subscribed-streams cache. Apps that mint many\n * dynamic targets (one per aggregate) should override via\n * {@link ActOptions.maxSubscribedStreams} based on expected concurrency.\n */\nexport const DEFAULT_MAX_SUBSCRIBED_STREAMS = 1000;\n\n/**\n * Default debounce window (ms) for `settle()` when neither the per-call\n * `SettleOptions.debounceMs` nor `ActOptions.settleDebounceMs` is set.\n * Coalesces commits in the same tick and small bursts; sub-perceptible\n * latency on the `\"settled\"` signal.\n */\nexport const DEFAULT_SETTLE_DEBOUNCE_MS = 10;\n\n// Re-export the autoclose config surface so operators can\n// `import { DEFAULT_AUTOCLOSE_CYCLE_MINUTES, resolveAutocloseConfig }\n// from \"@rotorsoft/act\"`. The implementation lives in\n// `internal/config.ts` (the single home for builder-facing config bags)\n// to keep this orchestrator file focused on the `Act` class.\nexport {\n type AutocloseConfig,\n type AutoclosePolicy,\n DEFAULT_AUTOCLOSE_CYCLE_MINUTES,\n DEFAULT_CLOSE_BATCH_SIZE,\n DEFAULT_CLOSE_YIELD_MS,\n resolveAutocloseConfig,\n} from \"./internal/index.js\";\n\n/**\n * Lifecycle events emitted by {@link Act}, mapped to their payload type.\n * Drives the typing of `emit` / `on` / `off` — the event-name argument\n * narrows its payload at the call site.\n *\n * The first parameter is kept (unused) for arity compatibility: `committed`\n * carries snapshots of whichever state each action targeted, so its honest\n * element type is `Snapshot<Schema, TEvents>` — the register map itself was\n * never the shape of any snapshot's state.\n */\nexport type ActLifecycleEvents<\n _TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n> = {\n committed: Snapshot<Schema, TEvents>[];\n acked: Lease[];\n blocked: BlockedLease[];\n settled: Drain<TEvents>;\n closed: CloseResult;\n /**\n * A **different process** committed an event to the same backing store.\n *\n * Fires only when the configured store implements\n * {@link Store.notify} and there is at least one registered reaction.\n * The orchestrator uses the same signal internally to wake `settle()`\n * — listeners get the raw payload for SSE fan-out, dashboards, and\n * audit logs.\n *\n * Local commits do *not* fire `notified` (use `committed` for those):\n * stores self-filter their own writes so this channel has a clean\n * cross-process semantic.\n */\n notified: StoreNotification;\n /**\n * A stream's sensitive-data payload was wiped via {@link Act.forget}.\n * Fires exactly once per successful `forget(stream)` call — idempotent\n * second calls (no PII left on the stream) return `eventCount: 0` and\n * do NOT re-emit. Apps that never call `forget()` never see this event.\n *\n * Listeners use it for the compliance side of GDPR / CCPA: audit log,\n * downstream cache busts, projection-side wipes that the framework\n * doesn't reach (e.g., search indexes, ETL caches). The framework's own\n * cache is invalidated by `forget()` itself before the event fires.\n */\n forgotten: { stream: string; at: Date; eventCount: number };\n /**\n * A store operation failed during the drain loop (ACT-984). Fires on\n * every failed drain cycle — typically a {@link StoreError} from a\n * degraded backend — carrying the orchestrator circuit breaker's state\n * after the failure (`open` means the drain loop has backed off and will\n * retry after the cooldown). Listen to alert on a degraded store; the\n * framework logs the same error regardless. Emitted only when a listener\n * is registered (Node's `EventEmitter` throws on an unhandled `\"error\"`).\n */\n error: { error: unknown; circuit: CircuitState };\n};\n\n/**\n * Options for {@link Act} construction (passed via {@link ActBuilder.build}).\n *\n * @property maxSubscribedStreams - Cap for the LRU set tracking already-\n * subscribed reaction streams. Default: {@link DEFAULT_MAX_SUBSCRIBED_STREAMS}.\n * @property settleDebounceMs - Debounce window (ms) used by `settle()` when\n * the caller doesn't pass `SettleOptions.debounceMs`. Tune this once per\n * Act instance instead of threading the value through every call site.\n * Default: {@link DEFAULT_SETTLE_DEBOUNCE_MS}.\n */\nexport type ActOptions<TLanes extends string = string> = {\n readonly maxSubscribedStreams?: number;\n readonly settleDebounceMs?: number;\n /**\n * Per-Act ports (ACT-501). When set, this Act runs against the\n * provided store + cache instead of the singletons — threaded via\n * AsyncLocalStorage so internals are unchanged. Both are required\n * together (a shared cache across distinct stores would collide on\n * stream keys). Omit for the singleton path.\n */\n readonly scoped?: Scoped;\n /**\n * Correlation-id generator for originating actions (ACT-404). When\n * omitted, Act uses {@link default_correlator}, which produces a\n * readable, time-monotonic-within-window, lowercase id of the form\n * `{state[:4]}-{action[:4]}-{ts}{rnd}` (18 chars).\n *\n * Reactions inherit `reactingTo.meta.correlation` so the chain stays\n * intact — the delegate is only consulted on originating commits and\n * for the close-the-books transaction.\n */\n readonly correlator?: Correlator;\n /** Restrict this process to a subset of declared lanes (ACT-1103). */\n readonly onlyLanes?: ReadonlyArray<TLanes>;\n /**\n * Subscribe to {@link Store.notify} on this instance (#803). Defaults\n * to `true`. Set `false` on instances that only commit and never\n * react — the subscriber-connection budget is the practical scaling\n * ceiling for the notify/listen pattern, and writer-only fleets\n * spend it for nothing when they subscribe to a channel they never\n * read. Commits still emit notifications (that's part of the\n * store's commit protocol); only the subscriber side is gated.\n */\n readonly listen?: boolean;\n /**\n * Run the local reaction pipeline on this instance (#803). Defaults\n * to `true`. Set `false` on writer-only or sidecar instances: drain\n * controllers' auto-cycle workers don't start, `correlate()` /\n * `drain()` / `settle()` become no-ops, and the notify handler\n * skips its drain-wakeup arm (but still emits the `notified`\n * lifecycle event so observability sidecars work).\n */\n readonly drain?: boolean;\n /**\n * Orchestrator circuit breaker for the drain loop (ACT-984). After\n * `failureThreshold` consecutive store failures the breaker opens and\n * the drain loop skips `claim()` for `cooldownMs` instead of hammering a\n * down backend, then allows a half-open trial. Out-of-range values throw\n * a `ZodError` at `act().build()`. Defaults: threshold 5, cooldown 30s.\n */\n readonly circuitBreaker?: CircuitBreakerOptions;\n /**\n * @deprecated Since #1175 this knob is accepted, validated, and\n * ignored. It paced the off-hours re-check of the pre-#1090 autoclose\n * sweep; the synthesized autoclose reaction now derives its re-check\n * directly from `autocloseWindow` — a tick landing outside the window\n * parks until the exact instant the window opens, so there is no\n * polling cadence to configure (and nothing minute-denominated on the\n * close surface). Still validated as an integer `[1, 1440]` so typos\n * keep failing loudly at `act().build()`. Will be removed in the next\n * major.\n */\n readonly autocloseCycleMinutes?: number;\n /**\n * @deprecated Dead since #1090 replaced the autoclose sweep with a\n * synthesized per-aggregate reaction — nothing pages the store in\n * batches anymore, so nothing reads this. Accepted and validated\n * (`[1, 1024]`) for compatibility; will be removed in the next major.\n */\n readonly closeBatchSize?: number;\n /**\n * @deprecated Dead since #1090 — the sweep that yielded between\n * successive `Store.truncate` calls no longer exists; closes are\n * staged per stream by the autoclose reaction. Accepted and validated\n * (`[0, 1000]`) for compatibility; will be removed in the next major.\n */\n readonly closeYieldMs?: number;\n /**\n * @deprecated Dead since #1090 — the sweep-side predicate try/catch\n * this flag steered no longer exists; a throwing policy predicate now\n * follows the reaction retry path (`blockOnError: false`, three\n * retries). Accepted for compatibility; will be removed in the next\n * major.\n */\n readonly closeOnError?: boolean;\n /**\n * Optional off-hours window restricting when autoclose evaluates. A\n * synthesized autoclose reaction that triggers outside the window\n * defers to the next instant the window opens — derived from the\n * window itself, no polling cadence. Hours are `[0, 23]` integers in\n * `timeZone` (IANA, default `\"UTC\"`, DST-correct); `start > end` is\n * an overnight window (e.g. `{ start: 22, end: 6 }`). Omit to\n * evaluate regardless of clock time.\n */\n readonly autocloseWindow?: {\n readonly start: number;\n readonly end: number;\n readonly timeZone?: string;\n };\n /**\n * Validate folded state against its declared Zod schema after every\n * reduction (ACT-1238). Off by default.\n *\n * When `true`, each time an event is folded into state — on the\n * command path (`do`), on `load`/replay, and inside projection-fold\n * projections — the merged full state is parsed against the owning\n * state's `state({ Name: schema })` schema. A reducer that produces\n * schema-violating state (the calculator divide-by-zero NaN class,\n * #1230) throws a {@link ValidationError} at the triggering event,\n * whose `target` names the state and the event (`<state>.<event>#<id>`)\n * — instead of the bad value propagating and surfacing hops later as a\n * confusing downstream error.\n *\n * This is a **debugging / CI aid, not a production guard**. Turn it on\n * in development and CI to catch total-reducer bugs at the source; the\n * framework already validates action inputs and emitted events, so the\n * reduced state is the one shape it otherwise trusts. The per-event\n * patch step is selected **once at `build()`** (the same way the\n * orchestrator picks bare vs trace-decorated store ops from the log\n * level): when `false` (the default) the fold loop is byte-identical to\n * a bare reduction — the validating patch step is never selected, so\n * there is no per-event cost, not even a branch.\n */\n readonly validateFoldedState?: boolean;\n};\n\n/** Reject `onlyLanes` entries that reference undeclared lanes. */\nfunction validate_only_lanes(\n options: ActOptions,\n lanes: ReadonlyArray<LaneConfig>\n): void {\n if (!options.onlyLanes || options.onlyLanes.length === 0) return;\n const declared = new Set<string>([\"default\", ...lanes.map((l) => l.name)]);\n const unknown = options.onlyLanes.filter((l) => !declared.has(l));\n if (unknown.length > 0)\n throw new Error(\n `ActOptions.onlyLanes references undeclared lane(s): ${unknown\n .map((l) => `\"${l}\"`)\n .join(\", \")}`\n );\n}\n\nexport class Act<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n TStateMap extends Record<string, Schema> = Record<string, never>,\n TActor extends Actor = Actor,\n> implements IAct<TEvents, TActions, TActor, TSchemaReg>\n{\n private _emitter = new EventEmitter();\n /** ACT-984: orchestrator-owned circuit breaker shared by all drain lanes. */\n private readonly _breaker: CircuitBreaker;\n /** #803: gate the `Store.notify` subscription side. */\n private readonly _listen: boolean;\n /** #803: gate the local reaction pipeline (drain controllers, settle, correlate). */\n private readonly _drain: boolean;\n /** Event names with at least one registered reaction (computed at build time) */\n private readonly _reactive_events: ReadonlySet<string>;\n /** One DrainController per active lane, keyed by lane name. */\n private readonly _drain_controllers: Map<\n string,\n DrainController<TEvents, TActions, TSchemaReg>\n >;\n /** Correlation state machine: lazy init, dynamic-resolver scan, periodic worker. */\n private readonly _correlate: CorrelateCycle<TSchemaReg, TEvents, TActions>;\n /** Debounced correlate→drain catch-up loop. */\n private readonly _settle: SettleLoop<TEvents>;\n /**\n * Disposer for the cross-process notify subscription, set up eagerly\n * during construction. Held as a promise because the subscription\n * itself may be async (the PG adapter checks out a dedicated client\n * and runs `LISTEN` before resolving). Resolves to `undefined` when\n * the store doesn't implement `notify` or there are no registered\n * reactions.\n *\n * **Contract:** the configured store must be injected via\n * {@link store}`(adapter)` *before* calling `act()...build()`. The\n * orchestrator wires notify against whatever store is current at\n * construction time — late injection after build is unsupported.\n */\n private readonly _notify_disposer: Promise<\n (() => void | Promise<void>) | undefined\n >;\n /** Public registry — kept as-is per the no-prefix-on-public convention. */\n public readonly registry: Registry<\n TSchemaReg,\n TEvents,\n TActions,\n keyof TStateMap & string\n >;\n /** Map of state name → state definition; populated by the builder. */\n private readonly _states: Map<string, State<any, any, any>>;\n /**\n * Emit a lifecycle event. The payload type is inferred from the event name\n * via {@link ActLifecycleEvents}.\n *\n * **Every listener is contained individually.** Lifecycle listeners are\n * observers — `observability.md` promises that a throwing one is \"contained,\n * not fatal\" — and containment belongs here rather than at each call site,\n * for two reasons the previous arrangement got wrong (#1437):\n *\n * - Wrapping the *emit* rather than each *listener* still let the first\n * thrower abort the rest: `EventEmitter.emit` stops dispatching on the\n * first exception, so a second `app.on(\"acked\", …)` never ran. The\n * documented \"the remaining sinks still fire\" was false whenever an event\n * had more than one listener. Same lesson as #1423, where guarding the\n * loop instead of each callback left every later SSE subscriber unserved.\n * - Only *some* call sites wrapped at all. The drain contained `acked` and\n * `blocked`; `committed`, `forgotten` and `close()`'s `closed` did not, so\n * a throwing listener rejected `do()`, `forget()` and `close()` **after**\n * their durable work had already landed. A caller retrying a \"failed\"\n * `do()` writes the event twice, since the framework has no dedup by\n * design.\n *\n * Containing here makes it a property of emitting, so a new lifecycle event\n * cannot reintroduce the gap by omission.\n *\n * Uses `rawListeners` so `once` wrappers still de-register themselves, and\n * returns \"had listeners\" to preserve the `EventEmitter.emit` contract.\n */\n emit<E extends keyof ActLifecycleEvents<TSchemaReg, TEvents, TActions>>(\n event: E,\n args: ActLifecycleEvents<TSchemaReg, TEvents, TActions>[E]\n ): boolean {\n const listeners = this._emitter.rawListeners(event as string);\n for (const listener of listeners) {\n try {\n listener(args);\n } catch (error) {\n this._logger.error(error, `${String(event)} listener threw`);\n }\n }\n return listeners.length > 0;\n }\n\n /**\n * The single store-failure handler: log it, then emit the `error`\n * lifecycle event. Wired into the circuit breaker's `on_error`, so it\n * runs on every `failed()` — drain / settle / autoclose just call\n * `breaker.failed(now, error)` and never log or emit themselves.\n *\n * The emit is guarded against Node's `EventEmitter` contract that an\n * unhandled `\"error\"` emission is rethrown (which would crash the process\n * from inside the drain catch); logging is unconditional so failures are\n * never silent.\n */\n private _emit_error(error: unknown, circuit: CircuitState): void {\n this._logger.error(error);\n if (this._emitter.listenerCount(\"error\") > 0)\n this.emit(\"error\", { error, circuit });\n }\n\n /**\n * Register a listener for a lifecycle event. The listener receives the\n * event-specific payload.\n */\n on<E extends keyof ActLifecycleEvents<TSchemaReg, TEvents, TActions>>(\n event: E,\n listener: (\n args: ActLifecycleEvents<TSchemaReg, TEvents, TActions>[E]\n ) => void\n ): this {\n this._emitter.on(event, listener);\n return this;\n }\n\n /**\n * Remove a previously registered lifecycle listener.\n */\n off<E extends keyof ActLifecycleEvents<TSchemaReg, TEvents, TActions>>(\n event: E,\n listener: (\n args: ActLifecycleEvents<TSchemaReg, TEvents, TActions>[E]\n ) => void\n ): this {\n this._emitter.off(event, listener);\n return this;\n }\n\n /** Batch handlers for static-target projections (target → handler) */\n private readonly _batch_handlers: Map<string, BatchHandler<TEvents>>;\n /** Event-sourcing handlers, optionally wrapped with trace decorators */\n private readonly _es: EsOps;\n /** Correlate/drain pipeline ops, optionally wrapped with trace decorators */\n private readonly _cd: DrainOps<TEvents>;\n /**\n * Event-name → owning state, computed at build time. The duplicate-event\n * guard in merge.ts ensures one event name maps to at most one state, so\n * this lookup is unambiguous. Used by `close()` to pick the right reducer\n * set when seeding a `restart` snapshot in multi-state apps.\n */\n private readonly _event_to_state: ReadonlyMap<string, State<any, any, any>>;\n /**\n * Event-name → lane fan-in for selective arming (ACT-1103). Built by\n * `classify_registry` once per build. `\"all\"` means at least one of\n * the event's reactions is a dynamic resolver (lane opaque until\n * runtime); a `Set<string>` lists the static lanes only that event's\n * reactions target.\n */\n private readonly _event_to_lanes: ReadonlyMap<string, EventLaneSet>;\n /**\n * Audit dependency bag (#723). Built once at construction; held as\n * an immutable snapshot of the registry state the audit module\n * needs. Lives in `internal/audit.ts` — this orchestrator never\n * carries audit logic, only the deps + a one-liner that hands them\n * over.\n */\n private readonly _audit_deps: AuditDeps;\n /** Logger resolved at construction time (after user port configuration) */\n private readonly _logger: Logger = log();\n /** Wraps a public-method body so internal `store()`/`cache()` resolve to the\n * per-Act ports (ACT-501). No-op when the Act is unscoped — so the singleton\n * path keeps reading fresh `store()`/`cache()` per call, which matters for\n * tests that dispose and re-seed mid-suite. */\n private readonly _scoped: <T>(fn: () => Promise<T>) => Promise<T>;\n\n /**\n * Correlation-id generator for originating actions. Bound at\n * construction from `options.correlator ?? default_correlator`. The\n * `do()` path passes this into the `_es.action` closure; close-cycle\n * uses it via {@link close_correlation}.\n */\n private readonly _correlator: Correlator;\n /** Pre-bound IAct methods reused across drain cycles. Only `do` varies per\n * payload (it captures the triggering event for reactingTo auto-inject). */\n private readonly _bound_do = this.do.bind(this);\n private readonly _bound_load = this.load.bind(this);\n private readonly _bound_query = this.query.bind(this);\n private readonly _bound_query_array = this.query_array.bind(this);\n private readonly _bound_forget = this.forget.bind(this);\n /** Reaction dispatchers built once and handed to run_drain_cycle each cycle. */\n private readonly _handle: Handle<TEvents>;\n private readonly _handle_batch: HandleBatch<TEvents>;\n /** Declared drain lanes (ACT-1103). */\n private readonly _lanes: ReadonlyArray<LaneConfig>;\n\n /**\n * Per-stream close serialization tails (#1222). Chains each stream's\n * windowed-close work behind the previous one so a manual\n * `app.close([{stream, before}])` and an autoclose windowed close for\n * the same stream never run their guard-free prune concurrently — the\n * manual path bypasses the `__autoclose__:X` drain lease that would\n * otherwise exclude them, so without this both closers archive the\n * same prefix. Process-local: both racers run on the same Act\n * instance. Entries are dropped once their tail resolves so the map\n * doesn't grow with distinct stream names.\n */\n private readonly _close_locks = new Map<string, Promise<unknown>>();\n\n /**\n * Run `work` under the per-stream close lock (#1222). Serializes\n * windowed-close critical sections for the same stream while letting\n * different streams proceed in parallel.\n */\n private _with_close_lock<T>(\n stream: string,\n work: () => Promise<T>\n ): Promise<T> {\n const prev = this._close_locks.get(stream) ?? Promise.resolve();\n // Chain after the previous holder regardless of how it settled — a\n // failed close must not wedge the stream's lock forever. The next\n // waiter chains off `next` (the work), so its start is gated on this\n // work completing.\n const next = prev.then(work, work);\n this._close_locks.set(stream, next);\n // Drop the tail once it settles, but only if it's still the current\n // one — a later waiter that already replaced it owns the entry now.\n const cleanup = () => {\n if (this._close_locks.get(stream) === next)\n this._close_locks.delete(stream);\n };\n next.then(cleanup, cleanup);\n return next;\n }\n\n /** Drain lanes declared via `.withLane(...)`. Implicit default not included. */\n get lanes(): ReadonlyArray<LaneConfig> {\n return this._lanes;\n }\n\n /**\n * Create a new Act orchestrator. Prefer the {@link act} builder over\n * direct construction — `act()...build()` wires the registry, merges\n * partial states, and collects batch handlers from registered slices\n * and projections in one pass.\n *\n * @param registry Schemas for every event and action across registered states\n * @param states Merged map of state name → state definition\n * @param batch_handlers Static-target projection batch handlers (target → handler)\n * @param options Tuning knobs — see {@link ActOptions}\n * @param lanes Declared drain lanes (ACT-1103). The builder collects\n * these from `.withLane(...)` calls. Slice 1 records them on the\n * instance; later slices fan out one `DrainController` per lane.\n * @param patch_fn The per-event patch step selected once by the builder\n * from `ActOptions.validateFoldedState` (ACT-1238) — `bare_patch` by\n * default, `validating_patch` when the flag is on. The builder uses\n * the same value for its projection-fold handlers, so there is a\n * single selection site. Defaults to `bare_patch` for direct\n * construction.\n */\n constructor(\n registry: Registry<TSchemaReg, TEvents, TActions, keyof TStateMap & string>,\n states: Map<string, State<any, any, any>> = new Map(),\n batch_handlers: Map<string, BatchHandler<any>> = new Map(),\n options: ActOptions = {},\n lanes: ReadonlyArray<LaneConfig> = [],\n patch_fn: PatchFn = bare_patch\n ) {\n this.registry = registry;\n this._states = states;\n this._batch_handlers = batch_handlers;\n this._lanes = lanes;\n validate_only_lanes(options, lanes);\n this._scoped = options.scoped\n ? (fn) => scoped.run(options.scoped!, fn)\n : (fn) => fn();\n this._correlator = options.correlator ?? default_correlator;\n this._es = build_es(this._logger, this._correlator, patch_fn);\n this._cd = build_drain<TEvents>(this._logger);\n // Reaction-level PII wrapping happens at build time inside `act-builder`:\n // reactions registered against an event with `sensitive(...)` fields get\n // a stripping handler closure; reactions against non-PII events keep\n // their original handler reference. So the dispatcher is PII-unaware.\n this._handle = build_handle<TEvents, TActions, TActor>({\n logger: this._logger,\n bound_do: this._bound_do,\n bound_load: this._bound_load,\n bound_query: this._bound_query,\n bound_query_array: this._bound_query_array,\n bound_forget: this._bound_forget,\n });\n this._handle_batch = build_handle_batch<TEvents>(this._logger);\n\n // The registry arrives complete and frozen from the builder — the\n // autoclose reactions were synthesized there, so classification sees\n // the finished shape and nothing here mutates it.\n const classification = classify_registry(this.registry, this._states);\n this._reactive_events = classification.reactive_events;\n this._event_to_state = classification.event_to_state;\n this._event_to_lanes = classification.event_to_lanes;\n this._listen = options.listen !== false;\n this._drain = options.drain !== false;\n\n // Composition sequence — each step builds one runtime subsystem from\n // the pieces above. Order matters: controllers read the breaker, the\n // audit bag reads the finalized controller set, settle reads the\n // correlate cycle.\n this._breaker = this._build_breaker(options);\n this._drain_controllers = this._build_drain_controllers(options, lanes);\n this._advise_orphaned_lanes(options, lanes);\n this._audit_deps = this._build_audit_deps();\n this._correlate = this._build_correlate(options, classification);\n this._settle = this._build_settle(options);\n\n // Auto-wire cross-process notify when the store supports it. Bound at\n // construction time — late `store(adapter)` injection after build won't\n // take effect. Scoped Acts bind against their own store.\n this._notify_disposer = this._wire_notify(options.scoped?.store ?? store());\n\n dispose(() => this.shutdown());\n }\n\n /**\n * Circuit breaker shared by every store-polling loop (drain, the settle\n * correlate, autoclose). Validates the knobs eagerly so out-of-range\n * values throw at build time, not on the first cycle tick.\n */\n private _build_breaker(options: ActOptions): CircuitBreaker {\n return new CircuitBreaker(\n resolveCircuitBreakerConfig(options.circuitBreaker),\n {\n on_error: (error, circuit) => this._emit_error(error, circuit),\n // Re-probe the store when the cooldown elapses, so recovery is\n // automatic even on the default lane (which has no periodic poller).\n // The wake fires `settle()`, which (in half-open) runs a real store\n // probe: for a dynamic-resolver app the probe is settle's correlate\n // (a store scan); for a static-reaction app correlate is a no-op that\n // records no health, so the probe is settle's DRAIN claim — either\n // way one success closes the breaker and every loop resumes, a\n // failure re-opens it and reschedules the wake. Settle does NOT close\n // the breaker off a no-op correlate (#1329) — only a real store op\n // (correlate scan or drain claim) records `passed()`.\n on_retry: () => {\n this.settle({ debounceMs: 0 });\n },\n }\n );\n }\n\n /**\n * One DrainController per active lane. The implicit \"default\" lane is\n * always present unless onlyLanes excludes it. Each controller filters\n * its claim() by its lane name; the legacy single-controller path is the\n * active set === { \"default\" } case with `lane: undefined` deps so\n * claim() doesn't filter (preserves the single-lane SQL planner shape\n * for apps that never call withLane).\n */\n private _build_drain_controllers(\n options: ActOptions,\n lanes: ReadonlyArray<LaneConfig>\n ): Map<string, DrainController<TEvents, TActions, TSchemaReg>> {\n const all_lanes = [\"default\", ...lanes.map((l) => l.name)];\n const only_set =\n options.onlyLanes && options.onlyLanes.length > 0\n ? new Set<string>(options.onlyLanes as readonly string[])\n : undefined;\n const active_lanes = only_set\n ? all_lanes.filter((n) => only_set.has(n))\n : all_lanes;\n const single_default_lane =\n active_lanes.length === 1 && active_lanes[0] === \"default\";\n const controllers = new Map<\n string,\n DrainController<TEvents, TActions, TSchemaReg>\n >();\n for (const name of active_lanes) {\n const cfg = lanes.find((l) => l.name === name);\n const controller = new DrainController({\n logger: this._logger,\n ops: this._cd,\n registry: this.registry,\n batch_handlers: this._batch_handlers,\n handle: this._handle,\n handle_batch: this._handle_batch,\n on_acked: (acked) => this.emit(\"acked\", acked),\n on_blocked: (blocked) => this.emit(\"blocked\", blocked),\n // Reaction-requested close. Runs the same close machinery as\n // `app.close` (tombstone guard + archive + atomic truncate) for the\n // targets a handler signalled via `CloseSignal`. No `correlate()`\n // here — the drain that produced these targets has already\n // correlated.\n on_close: async (targets) => {\n const close_actor = { id: \"$close\", name: \"close\" };\n const result = await run_close_cycle(targets, {\n reactive_events_size: this._reactive_events.size,\n event_to_state: this._event_to_state,\n load: this._es.load,\n tombstone: this._es.tombstone,\n logger: this._logger,\n correlation: close_correlation(this._correlator, close_actor),\n with_stream_lock: (stream, work) =>\n this._with_close_lock(stream, work),\n });\n this._forget_closed_subscriptions(result);\n // The close machinery above is deliberately NOT wrapped, so a\n // real StoreError reaches the breaker (#1388). The emit needs no\n // guard here: `Act.emit` contains each listener (#1437).\n this.emit(\"closed\", result);\n },\n breaker: this._breaker,\n // Re-scope the per-lane worker's auto-start ticks so their drain\n // resolves the scoped ports, not the singleton (#1191).\n run_scoped: this._scoped,\n // Pass lane only when a true per-lane controller is active.\n // The all-lanes (single default) case keeps lane=undefined so\n // adapter SQL collapses to the single-lane shape.\n lane: single_default_lane ? undefined : name,\n defaults: cfg && {\n streamLimit: cfg.streamLimit,\n leaseMillis: cfg.leaseMillis,\n },\n });\n // Auto-start a per-lane worker when the operator declared a\n // cycleMs — the intent of `withLane({cycleMs: 100})` is \"drive\n // this lane every 100 ms,\" independent of the Act-level settle\n // loop. unref()'d so the timer doesn't keep the process alive.\n // Writer-only instances (`drain: false`) construct the controller\n // but never run reactions locally, so the auto-start is skipped.\n if (cfg?.cycleMs !== undefined && options.drain !== false)\n controller.start(cfg.cycleMs);\n controllers.set(name, controller);\n }\n return controllers;\n }\n\n /**\n * Orphaned-lane startup advisory (#1220). When `onlyLanes` is set, this\n * instance builds a controller only for its slice of the declared lane\n * universe — every OTHER declared lane's stream is persisted (correlate\n * subscribes all static targets regardless of `onlyLanes`) but never\n * claimed here. If no peer worker deploys with those lanes in ITS\n * `onlyLanes`, their reactions accumulate forever, silently. A single\n * process can't verify the cluster invariant `∪ onlyLanes ⊇ declared\n * lanes`, so we surface the per-instance signal — \"these declared lanes\n * have no controller here\" — the same way the deprecated-event advisory\n * surfaces legacy events. No advisory when `onlyLanes` is unset (every\n * lane gets a controller) or covers every declared lane.\n */\n private _advise_orphaned_lanes(\n options: ActOptions,\n lanes: ReadonlyArray<LaneConfig>\n ): void {\n if (!options.onlyLanes || options.onlyLanes.length === 0) return;\n const active = new Set(this._drain_controllers.keys());\n const orphaned = [\"default\", ...lanes.map((l) => l.name)].filter(\n (name) => !active.has(name)\n );\n if (orphaned.length === 0) return;\n const list = orphaned.map((name) => `\"${name}\"`).join(\", \");\n this._logger.info(\n `Act declared ${orphaned.length} orphaned lane(s) on this instance: ${list}. ` +\n `onlyLanes excludes them, so no DrainController claims their streams here — ` +\n `their reactions accumulate un-drained unless a peer worker deploys with these ` +\n `lanes in its onlyLanes. Ensure the cluster invariant holds: the union of every ` +\n `worker's onlyLanes must cover every declared lane. ` +\n `See docs/docs/guides/production-checklist.md § Sizing lanes.`\n );\n }\n\n /**\n * Audit deps bag. Snapshotted after registry classification and\n * drain-controller build so the audit module sees the finalized lane\n * set. Held as an immutable bag — the orchestrator never carries audit\n * logic itself, only this typed contract.\n */\n private _build_audit_deps(): AuditDeps {\n return {\n store,\n logger: this._logger,\n event_to_state: this._event_to_state,\n states: this._states,\n // The DECLARED lane universe — the implicit \"default\" plus every\n // `.withLane(...)` name — NOT `_drain_controllers.keys()` (#1224).\n // An `onlyLanes`-filtered instance builds a controller only for its\n // slice of lanes, so keying off the active controller set would flag\n // a stream correctly assigned to an excluded-but-declared lane (one\n // another worker drains) as `unknown-lane`. The audit reports what's\n // structurally routable across the cluster, not what this process runs.\n declared_lanes: new Set([\"default\", ...this._lanes.map((l) => l.name)]),\n routed_events: new Set(this._event_to_lanes.keys()),\n };\n }\n\n /**\n * Correlate cycle over the classified registry. The cold-start callback\n * arms every controller — historical events may need processing —\n * except on writer-only instances (`drain: false`).\n */\n private _build_correlate(\n options: ActOptions,\n classification: ReturnType<\n typeof classify_registry<TSchemaReg, TEvents, TActions>\n >\n ): CorrelateCycle<TSchemaReg, TEvents, TActions> {\n return new CorrelateCycle({\n registry: this.registry,\n static_targets: classification.static_targets,\n has_dynamic_resolvers: classification.has_dynamic_resolvers,\n cd: this._cd,\n max_subscribed_streams:\n options.maxSubscribedStreams ?? DEFAULT_MAX_SUBSCRIBED_STREAMS,\n on_init: () => {\n if (this._drain && this._reactive_events.size > 0) this._arm_all();\n },\n // Re-scope the background `start_correlations` timer so its\n // correlate resolves the scoped ports, not the singleton (#1191).\n run_scoped: this._scoped,\n // Cold-start defer re-seed (#1221). Skipped on writer-only instances\n // (`drain: false`) — they run no local controllers to re-arm.\n on_init_async: this._drain\n ? () => this._seed_persisted_defers()\n : undefined,\n });\n }\n\n /**\n * Re-seed every active lane controller's process-local defer timer from\n * the store's persisted `deferred_at` (#1221). Runs once at cold start,\n * inside `CorrelateCycle.init`, after static targets are subscribed.\n *\n * The defer timer is worker memory: empty after a restart. A stream\n * deferred to a future due-time (the classic case: an idle autoclose\n * aggregate that deferred its terminal close) is durable in the store but\n * has nothing in memory to re-arm the drain — the controller disarms on\n * the first empty claim and, since the aggregate is idle, no commit ever\n * re-arms it. Reading the persisted schedule and seeding the owning lane's\n * timer restores the wake, so the close fires at the due-time.\n *\n * Streams whose lane has no controller on this instance (excluded by\n * `onlyLanes`) are skipped — a peer worker owns that lane's timer.\n */\n private async _seed_persisted_defers(): Promise<void> {\n const now = Date.now();\n // Paged — `query_streams` defaults to 100, and a stream sorting past\n // the first page would never get its timer re-armed. The failing case\n // is exactly the one described above: an idle aggregate no commit\n // ever re-arms.\n await walk_streams(store(), (pos) => {\n // Only future defers matter — a past-due schedule is claimable\n // already, so the ordinary armed drain picks it up.\n if (pos.deferred_at === undefined || pos.deferred_at <= now) return;\n // Route to the controller that owns the stream's lane. A missing\n // controller means the lane is excluded on this instance (onlyLanes) —\n // skip it, a peer worker owns that timer. The default lane's\n // controller is keyed \"default\" and matches an undefined stored lane.\n const controller = this._drain_controllers.get(pos.lane ?? \"default\");\n controller?.seed_defer(pos.stream, pos.deferred_at);\n });\n }\n\n /** Settle loop driving correlate + drain to quiescence. */\n private _build_settle(options: ActOptions): SettleLoop<TEvents> {\n return new SettleLoop<TEvents>(\n {\n // Scope the init like every other store-touching path — a bare\n // `this._correlate.init()` runs `store().subscribe(...)` against\n // the singleton for a scoped Act, so static targets never land on\n // the scoped store and `_initialized` then blocks a retry (#1191).\n init: () => this._scoped(() => this._correlate.init()),\n checkpoint: () => this._correlate.checkpoint,\n correlate: (q) => this.correlate(q),\n drain: (o) => this.drain(o),\n on_settled: (drain) => this.emit(\"settled\", drain),\n breaker: this._breaker,\n // Static-reaction apps' correlate is a no-op (no store call), so a\n // settle pass carries no store-health signal — don't let it record a\n // breaker success (#1329).\n correlate_probes_store: this._correlate.has_dynamic_resolvers,\n },\n options.settleDebounceMs ?? DEFAULT_SETTLE_DEBOUNCE_MS\n );\n }\n\n /** True after the first `shutdown()` call. Guards idempotency. */\n private _shutdown_promise: Promise<void> | undefined;\n\n /**\n * Per-instance teardown: remove lifecycle listeners, stop the\n * correlation worker, cancel any pending settle cycle, and tear\n * down the cross-process notify subscription.\n *\n * Idempotent — repeated calls return the same promise. Registered\n * automatically with the global `dispose()` registry at construction,\n * so process-wide `dispose()()` covers it; test helpers (or operators\n * that mint short-lived Acts) call it explicitly for prompt cleanup.\n */\n shutdown(): Promise<void> {\n if (!this._shutdown_promise) {\n this._shutdown_promise = (async () => {\n this._emitter.removeAllListeners();\n this.stop_correlations();\n this.stop_settling();\n this._breaker.stop();\n for (const c of this._drain_controllers.values()) c.stop();\n // `_wire_notify` swallows subscription errors and resolves to\n // `undefined`, so this promise never rejects.\n const disposer = await this._notify_disposer;\n if (disposer) await disposer();\n })();\n }\n return this._shutdown_promise;\n }\n\n /**\n * Subscribe to {@link Store.notify} when both the store and the\n * registry support it. Returns the disposer (or `undefined` when no\n * subscription was made). Errors during subscription are logged but\n * never thrown — `notify` is a hint, not a contract.\n */\n private async _wire_notify(\n s: Store\n ): Promise<(() => void | Promise<void>) | undefined> {\n if (this._reactive_events.size === 0) return undefined;\n if (!s.notify) return undefined;\n // #803: writer-only / single-instance deployments opt out of the\n // subscriber-connection cost. Commits still notify (that's the\n // store's commit protocol); only the subscriber side is gated.\n if (!this._listen) return undefined;\n try {\n return await s.notify((notification) => {\n // Generic concerns (lifecycle emit, drain wakeup, listener\n // error containment) live here so adapters only have to\n // handle their own wire format. Errors in user-registered\n // `notified` listeners or in our own bookkeeping are logged\n // and swallowed — the store's listener stays alive.\n try {\n this.emit(\"notified\", notification);\n // Wake once per commit when at least one event has a local\n // reaction. Avoids spurious wake-ups for remote commits\n // belonging to bounded contexts this process doesn't react to.\n // ACT-1103: selective arming via the shared helper — only the\n // lanes whose reactions match the notified events.\n // #803: the sidecar pattern (listen: true, drain: false)\n // wants the `notified` lifecycle event for observability\n // without engaging the local reaction pipeline.\n if (this._drain) {\n const armed = this._arm_for_event_names(\n notification.events.map((e) => e.name)\n );\n if (armed) this._settle.schedule({ debounceMs: 0 });\n }\n } catch (err) {\n this._logger.error(err, \"notified handler threw\");\n }\n });\n } catch (err) {\n this._logger.error(err, \"Store.notify subscription failed\");\n return undefined;\n }\n }\n\n /**\n * Executes an action on a state instance, committing resulting events.\n *\n * This is the primary method for modifying state. It:\n * 1. Validates the action payload against the schema\n * 2. Loads the current state snapshot\n * 3. Checks invariants (business rules)\n * 4. Executes the action handler to generate events\n * 5. Applies events to create new state\n * 6. Commits events to the store with optimistic concurrency control\n *\n * @template TKey - Action name from registered actions\n * @param action - The name of the action to execute\n * @param target - Target specification with stream ID and actor context\n * @param payload - Action payload matching the action's schema\n * @param options - Per-call dispatch options ({@link DoOptions}) —\n * `reactingTo` to thread correlation, `correlator` to override the\n * framework or orchestrator-level correlator for this call only.\n * @returns Array of snapshots for all affected states (usually one)\n *\n * @throws {ValidationError} If payload doesn't match action schema\n * @throws {InvariantError} If business rules are violated\n * @throws {ConcurrencyError} If another process modified the stream\n *\n * @example Basic action execution\n * ```typescript\n * const snapshots = await app.do(\n * \"increment\",\n * {\n * stream: \"counter-1\",\n * actor: { id: \"user1\", name: \"Alice\" }\n * },\n * { by: 5 }\n * );\n *\n * console.log(snapshots[0].state.count); // Current count after increment\n * ```\n *\n * @example With error handling\n * ```typescript\n * try {\n * await app.do(\n * \"withdraw\",\n * { stream: \"account-123\", actor: { id: \"user1\", name: \"Alice\" } },\n * { amount: 1000 }\n * );\n * } catch (error) {\n * if (error instanceof InvariantError) {\n * console.error(\"Business rule violated:\", error.description);\n * } else if (error instanceof ConcurrencyError) {\n * console.error(\"Concurrent modification detected, retry...\");\n * } else if (error instanceof ValidationError) {\n * console.error(\"Invalid payload:\", error.details);\n * }\n * }\n * ```\n *\n * @example Reaction triggering another action (reactingTo auto-injected)\n * ```typescript\n * const app = act()\n * .withState(Order)\n * .withState(Inventory)\n * .on(\"OrderPlaced\")\n * .do(async function reduceInventory(event, _stream, app) {\n * // Inside reaction handlers, reactingTo is auto-injected when omitted.\n * // The triggering event is used by default, maintaining the correlation chain.\n * await app.do(\n * \"reduceStock\",\n * { stream: \"inventory-1\", actor: { id: \"sys\", name: \"system\" } },\n * { amount: event.data.items.length }\n * );\n * // To use a different correlation, pass reactingTo explicitly:\n * // await app.do(\"reduceStock\", target, payload, { reactingTo: customEvent });\n * })\n * .to(\"inventory-1\")\n * .build();\n * ```\n *\n * @see {@link Target} for target structure\n * @see {@link Snapshot} for return value structure\n * @see {@link ValidationError}, {@link InvariantError}, {@link ConcurrencyError}\n */\n async do<TKey extends keyof TActions>(\n action: TKey,\n target: Target<TActor>,\n payload: Readonly<TActions[TKey]>,\n options?: DoOptions<TEvents>\n ) {\n return this._scoped(async () => {\n const snapshots = await this._es.action(\n this.registry.actions[action],\n action,\n target,\n payload,\n options\n );\n // Arm the drain when any committed event has reactions (ACT-1103:\n // arm only the lanes whose reactions match — events whose reactions\n // are all statically lane-resolved arm a subset; events with at\n // least one dynamic resolver fall back to _arm_all via the \"all\"\n // sentinel).\n if (this._reactive_events.size > 0)\n // Snapshots produced by `action()` always carry their committed\n // event — the optional `event?` on the type is for load()\n // snapshots, which don't reach this path.\n this._arm_for_event_names(\n snapshots.map((s) => (s.event as { name: string }).name)\n );\n this.emit(\"committed\", snapshots);\n return snapshots;\n });\n }\n\n /**\n * Loads the current state snapshot for a specific stream.\n *\n * Reconstructs the current state by replaying events from the event store.\n * Uses snapshots when available to optimize loading performance.\n *\n * Accepts either a State definition object or a state name string. When\n * using a string, the merged state (from partial states registered via\n * `.withState()`) is resolved by name.\n *\n * @template TNewState - State schema type\n * @template TNewEvents - Event schemas type\n * @template TNewActions - Action schemas type\n * @param state - The state definition or state name to load\n * @param stream - The stream ID (state instance identifier)\n * @param callback - Optional callback invoked with the loaded snapshot\n * @returns The current state snapshot for the stream\n *\n * @example Load by state definition\n * ```typescript\n * const snapshot = await app.load(Counter, \"counter-1\");\n * console.log(snapshot.state.count); // Current count\n * console.log(snapshot.patches); // Events since last snapshot\n * ```\n *\n * @example Load by state name (useful with partial states)\n * ```typescript\n * const snapshot = await app.load(\"Ticket\", \"ticket-123\");\n * console.log(snapshot.state.title); // Merged state from all partials\n * ```\n *\n * @example Load multiple states\n * ```typescript\n * const [user, account] = await Promise.all([\n * app.load(User, \"user-123\"),\n * app.load(BankAccount, \"account-456\")\n * ]);\n * ```\n *\n * @see {@link Snapshot} for snapshot structure\n */\n // Anonymous load (bare stream) — sensitive fields come back as REDACTED.\n async load<\n TNewState extends Schema,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n >(\n state: State<TNewState, TNewEvents, TNewActions>,\n stream: string,\n callback?: (snapshot: Snapshot<TNewState, TNewEvents>) => void,\n asOf?: AsOf\n ): Promise<Snapshot<TNewState, TNewEvents>>;\n async load<TKey extends keyof TStateMap & string>(\n name: TKey,\n stream: string,\n callback?: (snapshot: Snapshot<TStateMap[TKey], TEvents>) => void,\n asOf?: AsOf\n ): Promise<Snapshot<TStateMap[TKey], TEvents>>;\n // Auth-aware load — runs `.discloses(predicate)` against the supplied actor.\n async load<\n TNewState extends Schema,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n >(\n state: State<TNewState, TNewEvents, TNewActions>,\n target: LoadTarget<TActor>,\n callback?: (snapshot: Snapshot<TNewState, TNewEvents>) => void\n ): Promise<Snapshot<TNewState, TNewEvents>>;\n async load<TKey extends keyof TStateMap & string>(\n name: TKey,\n target: LoadTarget<TActor>,\n callback?: (snapshot: Snapshot<TStateMap[TKey], TEvents>) => void\n ): Promise<Snapshot<TStateMap[TKey], TEvents>>;\n async load<TNewState extends Schema>(\n stateOrName: State<TNewState, any, any> | string,\n streamOrTarget: string | LoadTarget<TActor>,\n callback?: (snapshot: Snapshot<any, any>) => void,\n asOf?: AsOf\n ): Promise<Snapshot<any, any>> {\n return this._scoped(async () => {\n let merged: State<any, any, any>;\n if (typeof stateOrName === \"string\") {\n const found = this._states.get(stateOrName);\n if (!found) throw new Error(`State \"${stateOrName}\" not found`);\n merged = found;\n } else {\n merged = this._states.get(stateOrName.name) || stateOrName;\n }\n // Normalize the two surfaces: bare-stream (default-deny — actor\n // undefined → REDACTED on the discloses check) vs LoadTarget\n // (auth-aware — actor flows into `.discloses(predicate)`).\n const target: LoadTarget<Actor> =\n typeof streamOrTarget === \"string\"\n ? {\n stream: streamOrTarget,\n actor: undefined as unknown as Actor,\n asOf,\n }\n : streamOrTarget;\n return await this._es.load(merged, target, callback);\n });\n }\n\n /**\n * Queries the event store for events matching a filter.\n *\n * Use this for analyzing event streams, generating reports, or debugging.\n * The callback is invoked for each matching event, and the method returns\n * summary information (first event, last event, total count).\n *\n * For small result sets, consider using {@link query_array} instead.\n *\n * @param query - Filter criteria — see {@link Query} for available fields\n * (`stream`, `name`, `after`, `before`, `created_after`, `created_before`,\n * `limit`, `with_snaps`, `stream_exact`)\n * @param callback - Optional callback invoked for each matching event\n * @returns Object with first event, last event, and total count\n *\n * @example Query all events for a stream\n * ```typescript\n * const { first, last, count } = await app.query(\n * { stream: \"counter-1\" },\n * (event) => console.log(event.name, event.data)\n * );\n * console.log(`Found ${count} events from ${first?.id} to ${last?.id}`);\n * ```\n *\n * @example Query specific event types\n * ```typescript\n * const { count } = await app.query(\n * { name: \"UserCreated\", limit: 100 },\n * (event) => {\n * console.log(\"User created:\", event.data.email);\n * }\n * );\n * ```\n *\n * @example Query events in time range\n * ```typescript\n * const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);\n * const { count } = await app.query({\n * created_after: yesterday,\n * stream: \"user-123\"\n * });\n * console.log(`User had ${count} events in last 24 hours`);\n * ```\n *\n * @see {@link query_array} for loading events into memory\n */\n async query(\n query: Query,\n callback?: (event: Committed<TEvents, keyof TEvents>) => void\n ): Promise<{\n first?: Committed<TEvents, keyof TEvents>;\n last?: Committed<TEvents, keyof TEvents>;\n count: number;\n }> {\n return this._scoped(async () => {\n let first: Committed<TEvents, keyof TEvents> | undefined;\n let last: Committed<TEvents, keyof TEvents> | undefined;\n const count = await store().query<TEvents>((e) => {\n const gated = this.registry.query_gate(e.name as string)(e);\n if (!first) first = gated;\n last = gated;\n callback?.(gated);\n }, query);\n return { first, last, count };\n });\n }\n\n /**\n * Queries the event store and returns all matching events in memory.\n *\n * **Use with caution** - this loads all results into memory. For large result sets,\n * use {@link query} with a callback instead to process events incrementally.\n *\n * @param query - The query filter (same as {@link query})\n * @returns Array of all matching events\n *\n * @example Load all events for a stream\n * ```typescript\n * const events = await app.query_array({ stream: \"counter-1\" });\n * console.log(`Loaded ${events.length} events`);\n * events.forEach(event => console.log(event.name, event.data));\n * ```\n *\n * @example Get recent events\n * ```typescript\n * const recent = await app.query_array({\n * stream: \"user-123\",\n * limit: 10\n * });\n * ```\n *\n * @see {@link query} for large result sets\n */\n async query_array(\n query: Query\n ): Promise<Committed<TEvents, keyof TEvents>[]> {\n return this._scoped(async () => {\n const events: Committed<TEvents, keyof TEvents>[] = [];\n await store().query<TEvents>(\n (e) => events.push(this.registry.query_gate(e.name as string)(e)),\n query\n );\n return events;\n });\n }\n\n /**\n * Wipe the sensitive-data payload for every event on the stream — see\n * {@link IAct.forget}. Application-level half of #566.\n *\n * Throws on adapters without `Store.forget_pii`, invalidates the cache\n * entry for the stream, emits the `forgotten` lifecycle event with the\n * row count. Idempotent: a second call returns `{eventCount: 0}` and\n * does NOT re-emit.\n *\n * @param stream - Target stream.\n * @returns `{eventCount}` — number of events whose PII column was wiped.\n */\n async forget(stream: string): Promise<{ eventCount: number }> {\n return this._scoped(async () => {\n const s = store();\n if (!s.forget_pii) {\n throw new Error(\n `Store does not implement forget_pii — adapter cannot comply with sensitive-data erasure. ` +\n `Use an adapter that declares pii_isolation: true (e.g. @rotorsoft/act on the in-memory store).`\n );\n }\n const eventCount = await s.forget_pii(stream);\n await cache().invalidate(stream);\n if (eventCount > 0) {\n this.emit(\"forgotten\", { stream, at: new Date(), eventCount });\n }\n return { eventCount };\n });\n }\n\n /**\n * Processes pending reactions by draining uncommitted events from the event store.\n *\n * Runs a single drain cycle:\n * 1. Polls the store for streams with uncommitted events\n * 2. Leases streams to prevent concurrent processing\n * 3. Fetches events for each leased stream\n * 4. Executes matching reaction handlers\n * 5. Acknowledges successful reactions or blocks failing ones\n *\n * Drain uses a dual-frontier strategy to balance processing of new streams (lagging)\n * vs active streams (leading). The ratio adapts based on event pressure.\n *\n * Call `correlate()` before `drain()` to discover target streams. For a higher-level\n * API that handles debouncing, correlation, and signaling automatically, use {@link settle}.\n *\n * @param options - Drain configuration — see {@link DrainOptions} for fields\n * (`streamLimit`, `eventLimit`, `leaseMillis`).\n * @returns Drain statistics with fetched, leased, acked, and blocked counts\n *\n * @example In tests and scripts\n * ```typescript\n * await app.do(\"createUser\", target, payload);\n * await app.correlate();\n * await app.drain();\n * ```\n *\n * @example In production, prefer settle()\n * ```typescript\n * await app.do(\"CreateItem\", target, input);\n * app.settle(); // debounced correlate→drain, emits \"settled\"\n * ```\n *\n * @see {@link settle} for debounced correlate→drain with lifecycle events\n * @see {@link correlate} for dynamic stream discovery\n * @see {@link start_correlations} for automatic correlation\n */\n async drain(options: DrainOptions = {}): Promise<Drain<TEvents>> {\n // Validate the runtime knobs before anything runs (a bad leaseMillis /\n // streamLimit / eventLimit throws ZodError here, not on the first cycle).\n resolveDrainConfig(options);\n // #803: writer-only instances skip the local reaction pipeline.\n // Return an empty Drain result so call sites that aggregate (e.g.,\n // `settle` listeners) keep working without special-casing.\n if (!this._drain)\n return { fetched: [], leased: [], acked: [], blocked: [] };\n return this._scoped(() => this._drain_all(options));\n }\n\n /** Arm every active lane controller (ACT-1103). */\n private _arm_all(): void {\n for (const c of this._drain_controllers.values()) c.arm();\n }\n\n /**\n * Arm only the lane controllers whose reactions match the supplied\n * event names (ACT-1103 selective arming). Events with any dynamic\n * resolver fall back to `_arm_all()` via the `\"all\"` sentinel — the\n * resolver's lane isn't known until correlate runs the function.\n * Events with no reactions are skipped; `_event_to_lanes` doesn't\n * carry them. Returns true when any controller was armed (used by\n * the notify handler to decide whether to schedule a settle).\n */\n private _arm_for_event_names(names: Iterable<string>): boolean {\n const to_arm = new Set<string>();\n for (const name of names) {\n const set = this._event_to_lanes.get(name);\n if (set === undefined) continue;\n if (set === ALL_LANES) {\n this._arm_all();\n return true;\n }\n for (const lane of set) to_arm.add(lane);\n }\n if (to_arm.size === 0) return false;\n for (const lane of to_arm) this._drain_controllers.get(lane)?.arm();\n return true;\n }\n\n /** Drain every active lane controller in parallel and aggregate.\n *\n * Parallel — not sequential — so a slow lane's in-flight handler does\n * not block a fast lane's claim/dispatch/ack cycle. Each controller's\n * `claim()` is independent (filtered by lane); the store's\n * `SKIP LOCKED` keeps cross-controller races safe. Lifecycle events\n * (`acked`, `blocked`) may interleave by lane — listeners filter via\n * `lease.lane`. */\n private async _drain_all(options: DrainOptions): Promise<Drain<TEvents>> {\n const results = await Promise.all(\n [...this._drain_controllers.values()].map((c) => c.drain(options))\n );\n const fetched: Drain<TEvents>[\"fetched\"] = [];\n const leased: Lease[] = [];\n const acked: Lease[] = [];\n const blocked: BlockedLease[] = [];\n for (const r of results) {\n fetched.push(...r.fetched);\n leased.push(...r.leased);\n acked.push(...r.acked);\n blocked.push(...r.blocked);\n }\n return { fetched, leased, acked, blocked };\n }\n\n /**\n * Discovers and registers new streams dynamically based on reaction resolvers.\n *\n * Correlation enables \"dynamic reactions\" where target streams are determined at runtime\n * based on event content. For example, you might create a stats stream for each user\n * when they perform certain actions.\n *\n * This method scans events matching the query and identifies new target streams based\n * on reaction resolvers. It then registers these streams so they'll be picked up by\n * the next drain cycle.\n *\n * @param query - Query filter to scan for new correlations\n * @param query - Scan filter — see {@link Query} for fields (typically\n * `{ after: <event-id>, limit: <count> }`)\n * @returns Object with newly leased streams and last scanned event ID\n *\n * @example Manual correlation\n * ```typescript\n * // Scan for new streams\n * const { leased, last_id } = await app.correlate({ after: 0, limit: 100 });\n * console.log(`Found ${leased.length} new streams`);\n *\n * // Save last_id for next scan\n * await saveCheckpoint(last_id);\n * ```\n *\n * @example Dynamic stream creation\n * ```typescript\n * const app = act()\n * .withState(User)\n * .withState(UserStats)\n * .on(\"UserLoggedIn\")\n * .do(async (event) => [\"incrementLoginCount\", {}])\n * .to((event) => ({\n * target: `stats-${event.stream}` // Dynamic target per user\n * }))\n * .build();\n *\n * // Discover stats streams as users log in\n * await app.correlate();\n * ```\n *\n * @see {@link start_correlations} for automatic periodic correlation\n * @see {@link stop_correlations} to stop automatic correlation\n */\n async correlate(\n query: Query = { after: -1, limit: 10 }\n ): Promise<{ subscribed: number; last_id: number }> {\n // Writer-only instances skip dynamic stream discovery. The\n // {subscribed, last_id} pair returns the no-op result; the\n // checkpoint stays where it was.\n if (!this._drain) return { subscribed: 0, last_id: -1 };\n return this._scoped(async () => {\n const result = await this._correlate.correlate(query);\n // Newly-subscribed streams must arm their lane controllers, same\n // as reset/unblock: a lane worker's tick can disarm on an empty\n // claim in the window before the subscription lands, and nothing\n // re-arms until an unrelated commit — starving the fresh stream\n // on an otherwise idle system.\n if (result.subscribed > 0 && this._reactive_events.size > 0)\n this._arm_all();\n return result;\n });\n }\n\n /**\n * Starts automatic periodic correlation worker for discovering new streams.\n *\n * The correlation worker runs in the background, scanning for new events and identifying\n * new target streams based on reaction resolvers. It maintains a sliding window that\n * advances with each scan, ensuring all events are eventually correlated.\n *\n * This is useful for dynamic stream creation patterns where you don't know all streams\n * upfront - they're discovered as events arrive.\n *\n * **Note:** Only one correlation worker can run at a time per Act instance.\n *\n * @param query - Query filter for correlation scans — see {@link Query}\n * (typically `{ after: -1, limit: 100 }`)\n * @param frequency - Correlation frequency in milliseconds (default: 10000)\n * @param callback - Optional callback invoked with newly discovered streams\n * @returns `true` if worker started, `false` if already running\n *\n * @example Start automatic correlation\n * ```typescript\n * // Start correlation worker scanning every 5 seconds\n * app.start_correlations(\n * { after: 0, limit: 100 },\n * 5000,\n * (leased) => {\n * console.log(`Discovered ${leased.length} new streams`);\n * }\n * );\n *\n * // Later, stop it\n * app.stop_correlations();\n * ```\n *\n * @example With checkpoint persistence\n * ```typescript\n * // Load last checkpoint\n * const lastId = await loadCheckpoint();\n *\n * app.start_correlations(\n * { after: lastId, limit: 100 },\n * 10000,\n * async (leased) => {\n * // Save checkpoint for next restart\n * if (leased.length) {\n * const maxId = Math.max(...leased.map(l => l.at));\n * await saveCheckpoint(maxId);\n * }\n * }\n * );\n * ```\n *\n * @see {@link correlate} for manual one-time correlation\n * @see {@link stop_correlations} to stop the worker\n */\n start_correlations(\n query: Query = {},\n frequency = 10_000,\n callback?: (subscribed: number) => void\n ): boolean {\n const started = this._correlate.start_polling(query, frequency, callback);\n return started;\n }\n\n /**\n * Stops the automatic correlation worker.\n *\n * Call this to stop the background correlation worker started by {@link start_correlations}.\n * This is automatically called when the Act instance is disposed.\n *\n * @example\n * ```typescript\n * // Start correlation\n * app.start_correlations();\n *\n * // Later, stop it\n * app.stop_correlations();\n * ```\n *\n * @see {@link start_correlations}\n */\n stop_correlations() {\n this._correlate.stop_polling();\n }\n\n /**\n * Cancels any pending or active settle cycle.\n *\n * @see {@link settle}\n */\n stop_settling() {\n this._settle.stop();\n }\n\n /**\n * Reset reaction stream watermarks and request a drain on the next\n * `drain()` / `settle()` cycle.\n *\n * Use this to replay events through projections (or other reaction targets)\n * after changing handler logic. Equivalent to calling `store().reset(streams)`\n * directly, but also raises the orchestrator's internal \"needs drain\" flag —\n * `store().reset(...)` alone leaves the flag untouched, so a settled app\n * would short-circuit and skip the replay.\n *\n * Pair with `app.settle()` (or a single `app.drain()` for small streams).\n * `settle()` loops correlate→drain until no progress is made, so one call\n * fully catches up paginated streams without forcing callers to roll\n * their own loop.\n *\n * @param input - Reaction target streams (e.g., projection names) to reset, or a {@link StreamFilter} for bulk operations\n * @returns Count of streams that were actually reset\n *\n * @example Rebuild a projection (production)\n * ```typescript\n * await app.reset([\"my-projection\"]);\n * app.settle({ eventLimit: 1000 }); // emits \"settled\" when fully replayed\n * ```\n *\n * @example Rebuild a projection (tests / scripts)\n * ```typescript\n * await app.reset([\"my-projection\"]);\n * await app.drain({ eventLimit: 1000 }); // small streams: one pass is enough\n * ```\n *\n * @see {@link Store.reset} for the underlying store primitive\n * @see {@link settle} for the debounced full-catch-up loop\n */\n async reset(input: string[] | StreamFilter): Promise<number> {\n return this._scoped(async () => {\n const count = await store().reset(input);\n if (count > 0 && this._reactive_events.size > 0) this._arm_all();\n return count;\n });\n }\n\n /**\n * Clear the blocked flag on streams without replaying their history.\n *\n * Use this to recover from a poison message after fixing the\n * underlying issue — the stream resumes from the next event after the\n * last successful ack, not from the beginning. Compare with\n * {@link reset}, which rebuilds from event 0 (suitable for projection\n * rebuilds, wrong for \"I fixed the bug, please retry\").\n *\n * Wraps `store().unblock(streams)` and raises the orchestrator's\n * internal \"needs drain\" flag so a settled app picks up the now-free\n * streams on the next cycle. Equivalent to calling `store().unblock(...)`\n * directly, but `store().unblock(...)` alone leaves the flag\n * untouched.\n *\n * @param input - Stream names to unblock, or a {@link StreamFilter} for bulk recovery\n * @returns Count of streams that were actually flipped (were blocked)\n *\n * @example Recover from a 4xx webhook after fixing the bug\n * ```typescript\n * await app.unblock([\"webhooks-out-customer-42\"]);\n * // The stream resumes from the next event, not from zero.\n * ```\n *\n * @see {@link Store.unblock} for the underlying store primitive\n * @see {@link reset} for the rebuild-from-zero alternative\n */\n async unblock(input: string[] | StreamFilter): Promise<number> {\n return this._scoped(async () => {\n const count = await store().unblock(input);\n if (count > 0 && this._reactive_events.size > 0) this._arm_all();\n return count;\n });\n }\n\n /**\n * Atomically wipe the store and rebuild it from an async stream of\n * committed events. The framework owns iteration, validation,\n * `drop_snapshots` filtering, `on_progress`, and the per-call\n * `old → new` causation remap; the adapter's {@link Store.restore}\n * driver supplies the transaction lifecycle and per-event insert.\n *\n * Throws if the adapter has no restore capability. Throws on the\n * first invalid event (negative version, malformed `created`) with\n * the running index in the message; atomic transaction rollback in\n * the adapter means a failing restore leaves the store byte-for-byte\n * unchanged.\n *\n * @param source - Async stream of events in target order. Streamed\n * rather than buffered so multi-million-event backups don't OOM.\n * Each event's original `id` is used as a causation lookup key but\n * never written through — adapters renumber densely.\n * @param opts - {@link ScanOptions}. `drop_snapshots` skips\n * `__snapshot__` events (counted in the result); `on_progress`\n * fires once per event.\n * @returns {@link ScanResult} with `kept`, `duration_ms`, and\n * `dropped` per-category counters.\n *\n * @example Round-trip a CSV backup\n * ```typescript\n * async function* parseCsv(blob: string) {\n * for (const line of blob.split(\"\\n\").slice(1)) {\n * const [id, name, data, stream, version, created, meta] = parse(line);\n * yield {\n * id: +id, name, data: JSON.parse(data), stream,\n * version: +version, created: new Date(created),\n * meta: JSON.parse(meta),\n * };\n * }\n * }\n * const result = await app.restore(parseCsv(csvBlob), {});\n * console.log(`Restored ${result.kept} events in ${result.duration_ms}ms`);\n * await cache().clear(); // operator's responsibility\n * ```\n *\n * @see {@link Store.restore} for the underlying driver-pattern primitive.\n */\n async restore(\n source: EventSource,\n opts: ScanOptions = {},\n sink?: EventSink\n ): Promise<ScanResult> {\n return this._scoped(async () => {\n const started = Date.now();\n // Dry-run: walk the source via scan without touching any sink\n // — same scan loop, no callback, no transaction, no capability\n // check. Returns the counts a destructive restore would land.\n if (opts.dry_run) {\n const partial = await scan(source, opts);\n return { ...partial, duration_ms: Date.now() - started };\n }\n // Default sink is the singleton store. Explicit `sink` lets\n // callers route to a different EventSink (another adapter, a\n // CsvFile, etc.) without binding the singleton.\n const target: EventSink =\n sink ??\n (() => {\n const s = store();\n if (!s.restore) throw new Error(\"adapter has no restore capability\");\n return s as EventSink;\n })();\n let kept = 0;\n let migrated = 0;\n let dropped = { closed_streams: 0, snapshots: 0 };\n await target.restore(async (callback) => {\n const partial = await scan(source, opts, callback);\n kept = partial.kept;\n migrated = partial.migrated;\n dropped = partial.dropped;\n });\n return { kept, migrated, dropped, duration_ms: Date.now() - started };\n });\n }\n\n /**\n * Return every currently-blocked stream position. Convenience wrapper\n * around `store().query_streams(cb, { blocked: true })` for the common\n * \"show me what's broken\" operational query.\n *\n * Results are ordered by stream name, paginated by `limit` (default\n * 100). Pass `after` to fetch the next page (keyset cursor on the\n * stream name). For richer queries — including blocked + source\n * filters, or full unblocked introspection — drop to\n * `store().query_streams(...)` directly.\n *\n * @returns Array of {@link StreamPosition} for currently-blocked streams.\n *\n * @example Discover and recover\n * ```typescript\n * const blocked = await app.blocked_streams();\n * console.table(blocked.map(({ stream, retry, error }) => ({ stream, retry, error })));\n *\n * // Operator investigates, then bulk-unblocks the family:\n * await app.unblock({ stream: \"^webhooks-out-\" });\n * ```\n */\n async blocked_streams(options?: {\n after?: string;\n limit?: number;\n }): Promise<StreamPosition[]> {\n return this._scoped(async () => {\n const positions: StreamPosition[] = [];\n await store().query_streams(\n (p) => {\n positions.push(p);\n },\n { blocked: true, after: options?.after, limit: options?.limit }\n );\n return positions;\n });\n }\n\n /**\n * Operator-driven store audit (#723).\n *\n * Walks the connected store and yields per-category findings —\n * each tagged with the remediation it suggests. Same operator-\n * driven category as `app.close()` / `app.reset()` /\n * `app.unblock()` / `app.blocked_streams()`: never auto-invoked by\n * the framework; the operator decides when to run it (CI gate,\n * scheduled job, ad-hoc forensics) and what to do with the\n * findings.\n *\n * Categories are independent — pass a subset to scope the work,\n * or omit to run everything:\n *\n * ```typescript\n * // Targeted: schema drift + deprecated-event load only\n * for await (const f of app.audit([\"schema\", \"deprecated-load\"], {\n * query: { created_after: lastScan },\n * thresholds: { deprecatedLoadShareMin: 0.10 },\n * })) {\n * await escalate(f);\n * }\n *\n * // Full audit, default thresholds\n * for await (const f of app.audit()) console.log(f);\n * ```\n *\n * Returns an `AsyncIterable` so callers can `break` early — the\n * underlying store paginations respect the iterator protocol and\n * stop cleanly. Each finding is emitted independently, so\n * pipelining into Slack / persistence / further analysis works\n * without buffering the full report in memory.\n *\n * Findings shape — see {@link AuditFinding}. The discriminated\n * union carries enough context for the operator to act on each\n * finding directly: stream id, event id, recommendation hints.\n *\n * @param categories - Subset of categories to run (default: all).\n * @param options - Query window + per-category thresholds.\n * @returns Async iterable of {@link AuditFinding}.\n */\n async *audit(\n categories?: AuditCategory[],\n options?: AuditOptions\n ): AsyncIterable<AuditFinding> {\n // Drive the audit generator one step at a time INSIDE `_scoped`, so the\n // `store()` calls in its body resolve the scoped bag during lazy\n // iteration. A plain `return audit(...)` would run the generator body in\n // the consumer's `for await` frame, outside any scope — resolving the\n // singleton store and auditing the wrong tenant (#1317). For a\n // non-scoped Act `_scoped(fn)` is just `fn()`, so this is a no-op.\n const it = audit(this._audit_deps, categories, options)[\n Symbol.asyncIterator\n ]();\n while (true) {\n const { value, done } = await this._scoped(() => it.next());\n if (done) break;\n yield value;\n }\n }\n\n /**\n * Bulk-update scheduling priority for streams matching `filter`.\n *\n * Operator-grade override of the `claim()` lagging-frontier\n * ordering (ACT-102). Useful when a long-running replay needs to\n * jump ahead of other lagging streams, or when a no-longer-urgent\n * job should yield slots back to the rest. Build-time priorities\n * (set via the resolver's `priority` field) are subject to a\n * `max()` invariant across reactions; this API ignores that and\n * sets the priority outright on every matching row.\n *\n * Filter shape mirrors {@link query} / {@link Store.query_streams}:\n * `stream` / `source` are regex by default, exact with the\n * `*_exact` flags; `blocked` restricts to blocked or unblocked\n * rows. **An empty filter (`{}`) updates every registered stream.**\n *\n * @param filter - Selection criteria (regex by default).\n * @param priority - New priority value. Set as-is — no clamp.\n * @returns Count of streams whose priority changed.\n *\n * @example Boost a specific projection mid-replay\n * ```typescript\n * await app.prioritize({ stream: \"^proj-orders$\", stream_exact: false }, 10);\n * ```\n *\n * @example Drop all audit projections to background\n * ```typescript\n * await app.prioritize({ source: \"^audit-\" }, -5);\n * ```\n *\n * @example Reset everyone to default\n * ```typescript\n * await app.prioritize({}, 0);\n * ```\n *\n * @see {@link Store.prioritize} for the underlying primitive\n * @see {@link claim} for how priority biases scheduling\n */\n async prioritize(filter: StreamFilter, priority: number): Promise<number> {\n return this._scoped(() => store().prioritize(filter, priority));\n }\n\n /**\n * Close the books — guard, archive, truncate, and optionally restart streams.\n *\n * Safely removes historical events from the operational store:\n *\n * 1. **Correlate** — discover pending reaction targets\n * 2. **Safety check** — skip streams with pending reactions (skipped when no reactive events)\n * 3. **Guard** — commit `__tombstone__` with `expectedVersion` to block concurrent writes\n * 4. **Load state** — for streams in `snapshots`, load final state while guarded (no races)\n * 5. **Archive** — user callback per stream (abort-all on failure, streams are guarded)\n * 6. **Truncate + seed** — atomic: delete all events, insert `__snapshot__` or `__tombstone__`\n * 7. **Cache** — invalidate (tombstoned) or warm (restarted)\n * 8. **Emit \"closed\"** — lifecycle event with results\n *\n * Targets carrying `before` take the **windowed** branch instead —\n * close the books on a rolling window: probe the min consumer\n * watermark (so the boundary never rises past a lagging reaction),\n * run the archive callback against the cutoff, then prune the prefix\n * below the closest safe `__snapshot__`. No tombstone guard (the\n * pre-cutoff prefix is immutable), no seed, cache untouched — the\n * stream stays live and keeps accepting actions. Requires the state\n * to snapshot via `.snap(...)`; no qualifying snapshot ⇒ the stream\n * lands in `skipped` (retry after the next snapshot). Windowed\n * entries in the result echo `before` and carry the surviving\n * boundary snapshot as `committed`.\n *\n * @param targets - Per-stream close options (stream, restart?, archive?, before?)\n * @returns `{ truncated: TruncateResult, skipped: string[] }`\n *\n * @example Archive and close\n * ```typescript\n * await app.close([\n * { stream: \"order-123\", archive: async () => { await archiveToS3(\"order-123\"); } },\n * { stream: \"order-456\" },\n * ]);\n * ```\n *\n * @example Close with restart (state loaded automatically after guard)\n * ```typescript\n * await app.close([\n * { stream: \"counter-1\", restart: true },\n * { stream: \"counter-2\" }, // tombstoned\n * ]);\n * ```\n *\n * @example Windowed close — keep the last 180 days of real events\n * ```typescript\n * const cutoff = new Date();\n * cutoff.setDate(cutoff.getDate() - 180);\n * await app.close([\n * {\n * stream: \"ledger-acme\",\n * before: cutoff,\n * archive: async () => { await archiveToS3(\"ledger-acme\", cutoff); },\n * },\n * ]);\n * ```\n */\n /**\n * After a close, forget any target whose subscription row the truncate\n * removed, so a later correlate can re-subscribe it (#1398). Restart\n * targets keep their row, so only fully-retired streams are forgotten.\n */\n private _forget_closed_subscriptions(result: CloseResult): void {\n const retired = [...result.truncated.entries()]\n .filter(([, r]) => r.committed.name === TOMBSTONE_EVENT)\n .map(([stream]) => stream);\n if (retired.length) this._correlate.forget_subscribed(retired);\n }\n\n async close(targets: CloseTarget[]): Promise<CloseResult> {\n if (!targets.length) return { truncated: new Map(), skipped: [] };\n\n return this._scoped(async () => {\n // Correlate first so dynamic reaction targets are discovered before\n // the safety check examines subscription positions.\n await this.correlate({ limit: 1000 });\n\n // Synthesize an actor for the close transaction so user-supplied\n // correlators can still tag tenant context / trace ids.\n const close_actor = { id: \"$close\", name: \"close\" };\n const result = await run_close_cycle(targets, {\n reactive_events_size: this._reactive_events.size,\n event_to_state: this._event_to_state,\n load: this._es.load,\n tombstone: this._es.tombstone,\n logger: this._logger,\n correlation: close_correlation(this._correlator, close_actor),\n with_stream_lock: (stream, work) => this._with_close_lock(stream, work),\n });\n\n this._forget_closed_subscriptions(result);\n this.emit(\"closed\", result);\n return result;\n });\n }\n\n /**\n * Debounced, non-blocking correlate→drain cycle.\n *\n * Call this after `app.do()` (or `app.reset()`) to schedule a background\n * drain. Multiple rapid calls within the debounce window are coalesced\n * into a single cycle. Runs correlate→drain in a loop until a pass makes\n * no progress — no new subscriptions, no acks, no blocks — then emits\n * the `\"settled\"` lifecycle event. This means a single `settle()` call\n * fully catches up paginated streams (e.g. after `reset()` on a long\n * projection) without forcing callers to loop.\n *\n * @param options - Settle configuration — see {@link SettleOptions} for fields:\n * `debounceMs` (default 10), `correlate` (default `{ after: -1, limit: 100 }`),\n * `maxPasses` (default `Infinity` — kill-switch for runaway loops),\n * `streamLimit` (default 10), `eventLimit` (default 10),\n * `leaseMillis` (default 10000).\n *\n * @example API mutations\n * ```typescript\n * await app.do(\"CreateItem\", target, input);\n * app.settle(); // non-blocking, returns immediately\n *\n * app.on(\"settled\", (drain) => {\n * // notify SSE clients, invalidate caches, etc.\n * });\n * ```\n *\n * @see {@link drain} for single synchronous drain cycles\n * @see {@link correlate} for manual correlation\n */\n settle(options: SettleOptions = {}): void {\n // Validate the runtime knobs before anything runs (a bad debounceMs /\n // leaseMillis / maxPasses throws ZodError here, not on the first pass).\n resolveSettleConfig(options);\n // #803: writer-only instances skip settle entirely. The bootstrap\n // pattern `app.on(\"committed\", () => app.settle())` keeps working —\n // it just runs zero work on writers.\n if (!this._drain) return;\n this._settle.schedule(options);\n }\n}\n","/**\n * @module event-versions\n * @category Internal\n *\n * Auto-deprecation of legacy event versions via the `_v<digits>` naming\n * convention (ACT-403).\n *\n * Act's schema-evolution pattern keeps the old and new event names alive\n * forever — the old name on the read path (reducers), the new on the write\n * path (emissions). This module reads the convention to identify legacy\n * versions automatically; the framework then enforces \"emit only the\n * current version\" at build time and warns at runtime for dynamic emits.\n *\n * Convention pin: only `_v<digits>` with digits ≥ 2 counts as a version\n * suffix. `Foo_v1` is just a literal event name (the base `Foo` is\n * implicitly v1). Pinning here keeps the contract surface small.\n *\n * @internal\n */\n\nconst VERSION_SUFFIX = /^(.+?)_v(\\d+)$/;\n\ntype Versioned = { version: number; name: string };\n\n/**\n * Splits an event name into (base, version). Names without a `_v<n≥2>`\n * suffix are returned as (name, 1) — the base is its own implicit v1.\n */\nfunction parse(name: string): { base: string; version: number } {\n const m = name.match(VERSION_SUFFIX);\n if (m) {\n const v = Number.parseInt(m[2], 10);\n if (v >= 2) return { base: m[1], version: v };\n }\n return { base: name, version: 1 };\n}\n\n/**\n * Returns the set of event names that are deprecated by virtue of having\n * a higher-numbered sibling in the registry. The highest version in each\n * group is the current version; every lower version is deprecated.\n *\n * Gaps are allowed: `{Foo, Foo_v3}` → `Foo` is deprecated, `Foo_v3` is\n * current. The framework picks the max regardless of contiguity.\n *\n * Single-version groups (no siblings) yield no deprecations.\n *\n * @internal\n */\nexport function deprecated_event_names(names: Iterable<string>): Set<string> {\n const groups = new Map<string, Versioned[]>();\n for (const name of names) {\n const { base, version } = parse(name);\n const list = groups.get(base);\n if (list) list.push({ version, name });\n else groups.set(base, [{ version, name }]);\n }\n const deprecated = new Set<string>();\n for (const list of groups.values()) {\n if (list.length < 2) continue;\n // Two names mapping to the same numeric version (e.g. a leading-zero\n // `Foo_v02` alongside `Foo_v2`) can't both be a distinct version — one\n // is a typo. Left unguarded, the sort below would flag whichever lands\n // second, so declaration order would decide which one is \"current\",\n // and the real current event could be marked deprecated (a static\n // `.emit(...)` on it would then throw at build). Reject the collision\n // with a clear, order-independent error instead.\n const by_version = new Map<number, string>();\n for (const { version, name } of list) {\n const clash = by_version.get(version);\n if (clash)\n throw new Error(\n `duplicate event version: ${clash} and ${name} both map to version ${version} — ` +\n \"leading zeros in a `_v<n>` suffix are not allowed; use a single canonical spelling\"\n );\n by_version.set(version, name);\n }\n list.sort((a, b) => b.version - a.version); // descending\n // index 0 is current; the rest are deprecated\n for (let i = 1; i < list.length; i++) deprecated.add(list[i].name);\n }\n return deprecated;\n}\n\n/**\n * Given a deprecated event name and the full set of event names in its\n * registry, returns the current (highest-version) sibling. Used to build\n * actionable error messages — \"use `Foo_v3` instead.\"\n *\n * Returns `undefined` if the event has no higher-versioned sibling (which\n * means the caller's classification is stale or wrong).\n *\n * @internal\n */\nexport function current_version_of(\n deprecated_name: string,\n all_names: Iterable<string>\n): string | undefined {\n const target = parse(deprecated_name);\n let highest: Versioned | undefined;\n for (const name of all_names) {\n const { base, version } = parse(name);\n if (base !== target.base) continue;\n if (!highest || version > highest.version) highest = { version, name };\n }\n return highest && highest.version > target.version ? highest.name : undefined;\n}\n","import type { QueryStreams, Store, StreamPosition } from \"../types/index.js\";\n\n/** Streams read per page when walking the whole table. */\nexport const DEFAULT_STREAM_PAGE = 500;\n\n/**\n * Walks EVERY stream matching `query`, paging with the keyset cursor.\n *\n * `Store.query_streams` defaults to `limit: 100`, so a caller that wants\n * the whole table must page — passing no query silently truncates at the\n * first page, which is a false all-clear for anything that reports on\n * what it found.\n *\n * The cursor is the last stream name the callback saw; results are\n * ordered by stream name, so a short page means the walk is done.\n *\n * @param store - Store to walk.\n * @param callback - Invoked once per matching position, in name order.\n * @param query - Optional filter. A caller-supplied `limit` sets the page\n * size (the walk still visits every match); `after` seeds the cursor.\n * @returns The total number of positions emitted.\n *\n * @internal\n */\nexport async function walk_streams(\n store: Store,\n callback: (position: StreamPosition) => void,\n query?: Omit<QueryStreams, \"after\" | \"limit\"> & {\n after?: string;\n limit?: number;\n }\n): Promise<number> {\n const page_size = query?.limit ?? DEFAULT_STREAM_PAGE;\n let after = query?.after;\n let total = 0;\n for (;;) {\n let last: string | undefined;\n const { count } = await store.query_streams(\n (position) => {\n last = position.stream;\n callback(position);\n },\n { ...query, after, limit: page_size }\n );\n total += count;\n if (count < page_size) return total;\n after = last;\n }\n}\n","/**\n * @module audit\n * @category Internal\n *\n * Operator-driven store audit (#723).\n *\n * Walks the connected store and yields per-category {@link AuditFinding}s.\n * Each category answers a different \"what should I do with this store?\"\n * question and pairs with a remediation:\n *\n * - `schema` → fix the data model (poison events, unknown names)\n * - `close-candidate` → `app.close([...])`\n * - `restart-candidate` → `app.close([{stream, restart:true}, …])`\n * - `deprecated-load` → `app.close([...])` on the heaviest carriers\n * - `reaction-health` → `app.unblock(...)` / `app.reset(...)`\n * - `snapshot-drift` → manual `load({snap:true})` or wait for policy\n * - `routing-health` → restart-with-new-config to re-lane\n * - `correlation-gaps` → fix upstream correlator misconfig\n * - `clock-anomalies` → infra remediation (clock skew)\n *\n * ## Single-scan multiplex (efficiency contract)\n *\n * Earlier draft had each category run its own `store.query(...)`,\n * which meant N requested categories → N table walks. Bad for large\n * stores. Refactored to a pass-based design: each category is a\n * factory that returns an {@link AuditPass} with optional per-row\n * callbacks (`on_event` / `on_stream` / `on_stat`) and a `finalize` hook\n * for any second-pass work. The dispatcher determines the UNION of\n * required data sources, runs each *once*, and broadcasts each row\n * to all interested passes. Worst case: three scans total (events,\n * streams, stats) regardless of how many categories the operator\n * requested. Most categories also share state — close-candidate and\n * restart-candidate both consume the same `on_stat` stream; schema,\n * correlation-gaps, and clock-anomalies all hang off the same\n * `on_event` broadcast.\n *\n * Categories that need follow-up work (snapshot-drift's per-stream\n * snapshot lookup, correlation-gaps' orphan-id check after collecting\n * ids) do that in their `finalize` hook with their own targeted store\n * calls — keeps the shared scan path minimal.\n *\n * Isolated from orchestration internals — `act.ts` builds the\n * {@link AuditDeps} bag at `.build()` time and hands it here via\n * a one-liner. The audit module never reaches into\n * `internal/{event-sourcing,drain-cycle,settle,close-cycle}.ts`; it\n * only reads through the deps interface and the public `Store`\n * surface. Same shape as `act-tck` within the workspace — a peer of\n * orchestration, not entangled with its private mechanics.\n *\n * @internal\n */\n\nimport { SNAP_EVENT } from \"../ports.js\";\nimport type {\n AuditCategory,\n AuditFinding,\n AuditOptions,\n Committed,\n Logger,\n Schemas,\n State,\n Store,\n StreamPosition,\n StreamStats,\n} from \"../types/index.js\";\nimport {\n current_version_of,\n deprecated_event_names,\n} from \"./event-versions.js\";\nimport { pii_fields } from \"./sensitive.js\";\nimport { walk_streams } from \"./walk-streams.js\";\n\n/**\n * Snapshot of orchestrator state the audit reads. Built once at\n * `app.build()`; the audit treats it as immutable for the duration\n * of a call. The orchestrator never passes its own private maps in\n * directly — this bag is the abstraction boundary so a future\n * orchestration refactor can't accidentally entangle with audit\n * logic.\n */\nexport type AuditDeps = {\n readonly store: () => Store;\n readonly logger: Logger;\n /** event-name → state that registers it (for schema validation). */\n readonly event_to_state: ReadonlyMap<string, State<any, any, any>>;\n /** state-name → state (for snapshot-supported check on restart-candidate). */\n readonly states: ReadonlyMap<string, State<any, any, any>>;\n /** Declared drain lanes (for routing-health unknown-lane). */\n readonly declared_lanes: ReadonlySet<string>;\n /**\n * Event names that the registry has at least one reaction for —\n * used by routing-health to detect \"registered but unrouted\"\n * events. Normalized down from the internal `event_to_lanes` map\n * (which carries lane-set details audit doesn't need).\n */\n readonly routed_events: ReadonlySet<string>;\n};\n\n/**\n * Defaults applied when the operator doesn't override via\n * {@link AuditOptions.thresholds}. Values land where most workloads\n * find them operationally useful — operators can tune per call.\n */\nconst DEFAULTS = {\n idle_days: 90,\n restart_min: 10_000,\n stuck_minutes: 30,\n deprecated_min: 0.1,\n drift_min: 500,\n near_block: 3,\n};\n\nconst ALL_CATEGORIES = [\n \"schema\",\n \"close-candidate\",\n \"restart-candidate\",\n \"deprecated-load\",\n \"reaction-health\",\n \"snapshot-drift\",\n \"routing-health\",\n \"correlation-gaps\",\n \"clock-anomalies\",\n] as const satisfies readonly AuditCategory[];\n\n/**\n * A single audit category, expressed as a stream-consumer:\n *\n * - `on_event` / `on_stream` / `on_stat` are called by the dispatcher\n * during the shared scans. Each is optional; the dispatcher uses\n * the presence/absence to decide which scans to run.\n * - `finalize` runs after all shared scans complete. Categories that\n * need targeted follow-up store calls (snapshot-drift fetches the\n * last `__snapshot__` per drifted stream; correlation-gaps cross-\n * checks causations against the collected id set) do that here.\n * - `drain` is called last and returns the accumulated findings.\n */\ntype AuditPass = {\n category: AuditCategory;\n on_event?: (e: Committed<Schemas, string>) => void;\n on_stream?: (p: StreamPosition) => void;\n on_stat?: (stream: string, s: StreamStats<Schemas>) => void;\n finalize?: (deps: AuditDeps) => Promise<void>;\n drain: () => AuditFinding[];\n};\n\ntype PassFactory = (deps: AuditDeps, options: AuditOptions) => AuditPass;\n\n/**\n * Top-level audit dispatcher. Single-scan multiplex: each requested\n * category contributes a `AuditPass`, the dispatcher determines the\n * union of required data sources (events / streams / stats), runs\n * each once, broadcasts rows, and yields per-category findings in\n * the order the categories were requested.\n *\n * Callers can `break` the iteration early — the underlying scan\n * loops have already completed by the time yield starts, so early\n * break only saves the iteration over already-collected findings.\n * (Per-row early termination during a scan isn't feasible without\n * coordination across passes; the audit is bounded by `options.query`\n * scoping rather than mid-scan cancellation.)\n */\nexport async function* audit(\n deps: AuditDeps,\n categories?: AuditCategory[],\n options: AuditOptions = {}\n): AsyncIterable<AuditFinding> {\n const requested = new Set<AuditCategory>(categories ?? [...ALL_CATEGORIES]);\n // Preserve a deterministic category order (matches ALL_CATEGORIES\n // declaration) so output ordering doesn't depend on the order\n // operators list categories in their call.\n const ordered_categories = ALL_CATEGORIES.filter((c) => requested.has(c));\n const passes: AuditPass[] = ordered_categories.map((c) =>\n PASS_FACTORIES[c](deps, options)\n );\n\n // Determine scan needs. `some(...)` short-circuits — three trivial\n // walks at worst.\n const need_stats = passes.some((p) => p.on_stat !== undefined);\n const need_streams = passes.some((p) => p.on_stream !== undefined);\n const need_events = passes.some((p) => p.on_event !== undefined);\n\n if (need_stats) {\n // Exclude `__snapshot__` so `head` and `count` are DOMAIN figures.\n // A snapshot is committed right after the domain event that triggered\n // it, so without this the head of any snapshotting stream is\n // `__snapshot__` — and every pass that gates on the head name\n // (`startsWith(\"__\")` → \"already closed\") silently skips the stream.\n // Same reasoning as `scan_stream_heads` in the close cycle.\n //\n // `__tombstone__` is deliberately NOT excluded: a tombstoned stream\n // really is closed, and the head-name gates are what recognize it.\n const stats = await deps\n .store()\n .query_stats<Schemas>(\n {},\n { count: true, names: true, exclude: [SNAP_EVENT] }\n );\n for (const [stream, s] of stats) {\n for (const p of passes) p.on_stat?.(stream, s);\n }\n }\n\n if (need_streams) {\n // Paged — `query_streams` defaults to 100, and an audit that inspects\n // only the first page reports a false all-clear for every stream that\n // sorts past it.\n await walk_streams(deps.store(), (pos) => {\n for (const p of passes) p.on_stream?.(pos);\n });\n }\n\n if (need_events) {\n await deps.store().query<Schemas>((event) => {\n for (const p of passes) p.on_event?.(event);\n }, options.query);\n }\n\n // Async post-processing (per-stream queries, second-pass orphan\n // detection). Serial to avoid pool contention; categories are\n // independent so order doesn't matter semantically.\n for (const p of passes) await p.finalize?.(deps);\n\n // Yield findings in requested-category order.\n for (const p of passes) {\n for (const f of p.drain()) yield f;\n }\n}\n\n// =================== Pass factories ===================\n//\n// Each category is implemented as a closure-bound `AuditPass`. The\n// factory captures `deps` + relevant options + a `findings` array;\n// the returned pass exposes the per-row hooks the dispatcher calls.\n//\n// All findings are accumulated in a per-pass `findings` buffer and\n// returned from `drain()`. No yield-during-scan — that would couple\n// the pass to async iteration semantics and prevent the shared-scan\n// multiplexing.\n\n/**\n * `schema` — every event in the audit window is parsed against the\n * Zod schema the registry currently declares for its name. Two\n * failure modes: `unknown_event_name` (event sits on disk, registry\n * has no entry) and `schema_validation_failed` (event matches a\n * known name but fails the current Zod schema).\n */\nconst make_schema_pass: PassFactory = (deps) => {\n const findings: AuditFinding[] = [];\n return {\n category: \"schema\",\n on_event(event) {\n const name = String(event.name);\n const state = deps.event_to_state.get(name);\n if (!state) {\n // Skip framework markers — they're not user-declared.\n if (name.startsWith(\"__\")) return;\n findings.push({\n category: \"schema\",\n stream: event.stream,\n event_id: event.id,\n name,\n reason: \"unknown_event_name\",\n });\n return;\n }\n const schema = state.events[name];\n // `sensitive()` keys are split out of `data` into the pii sidecar at\n // commit — their absence from `data` is correct, not corruption. The\n // pass reads raw stored rows, so parsing against the full schema\n // reported every healthy sensitive event as invalid, one finding per\n // event, burying the real ones (#1424). Omit those keys instead; the\n // rest of the payload is still validated.\n const sensitive = pii_fields(schema);\n let parse_schema = schema;\n if (sensitive.length > 0) {\n const omitter = (\n schema as unknown as {\n omit?: (mask: Record<string, true>) => typeof schema;\n }\n ).omit;\n if (typeof omitter !== \"function\") {\n // A non-object schema (e.g. a union) whose variants carry pii —\n // the split keys can't be masked off, so any parse here is a\n // guaranteed false positive. Skip rather than cry wolf.\n return;\n }\n parse_schema = omitter.call(\n schema,\n Object.fromEntries(sensitive.map((f) => [f, true as const]))\n );\n }\n const parsed = parse_schema.safeParse(event.data);\n if (!parsed.success) {\n findings.push({\n category: \"schema\",\n stream: event.stream,\n event_id: event.id,\n name,\n reason: \"schema_validation_failed\",\n zod_error: parsed.error,\n });\n }\n },\n drain: () => findings,\n };\n};\n\n/**\n * `deprecated-load` — workspace-wide event-name histogram classified\n * by the framework's `_v<digits>` rule. Built from the shared `on_stat`\n * stream — accumulates per-name + per-stream totals in memory, then\n * emits one finding per deprecated event above the threshold during\n * `drain`.\n */\n/**\n * Per-state deprecation classification — mirrors the builder/registry\n * (`registry.deprecated_events(state_name)`), which group `_v<n>` families\n * strictly within one state's own event set. Classifying over the global\n * event-name union instead would conflate same-stem events across\n * unrelated states (a false-positive migration finding) and even throw on\n * a cross-state leading-zero version collision the builder accepted (#1310).\n * Returns a map of deprecated event name → its current (highest) sibling.\n */\nconst classify_deprecated_by_state = (\n deps: AuditDeps\n): ReadonlyMap<string, string> => {\n const names_by_state = new Map<State<any, any, any>, Set<string>>();\n for (const [name, state] of deps.event_to_state) {\n let set = names_by_state.get(state);\n if (!set) {\n set = new Set();\n names_by_state.set(state, set);\n }\n set.add(name);\n }\n const deprecated_to_current = new Map<string, string>();\n for (const names of names_by_state.values()) {\n for (const name of deprecated_event_names(names)) {\n // `current_version_of` is guaranteed defined for a deprecated name\n // within its own state's family.\n deprecated_to_current.set(name, current_version_of(name, names)!);\n }\n }\n return deprecated_to_current;\n};\n\nconst make_deprecated_load_pass: PassFactory = (deps, options) => {\n const share_min =\n options.thresholds?.deprecated_min ?? DEFAULTS.deprecated_min;\n const totals = new Map<string, number>();\n const per_stream = new Map<string, Map<string, number>>();\n return {\n category: \"deprecated-load\",\n on_stat(stream, { names }) {\n // Contract: query_stats was called with `{names: true}`,\n // so adapter populates `names` with positive integer counts.\n // No runtime fallback needed.\n for (const [name, count] of Object.entries(names!)) {\n totals.set(name, (totals.get(name) ?? 0) + count!);\n let m = per_stream.get(name);\n if (!m) {\n m = new Map();\n per_stream.set(name, m);\n }\n m.set(stream, count!);\n }\n },\n drain() {\n const findings: AuditFinding[] = [];\n const grand = [...totals.values()].reduce((s, n) => s + n, 0);\n if (grand === 0) return findings;\n // Per-state deprecation classification (not on-disk-driven, and not\n // over the global event-name union — see #1310).\n const deprecated = classify_deprecated_by_state(deps);\n const sorted = [...deprecated.keys()]\n .map((name) => ({ name, count: totals.get(name) ?? 0 }))\n .sort((a, b) => b.count - a.count);\n for (const { name, count } of sorted) {\n if (count === 0) continue;\n if (count / grand < share_min) continue;\n // `classify_deprecated_by_state` maps every deprecated name to its\n // current (highest-version) sibling within the same state.\n const current_version = deprecated.get(name)!;\n // per_stream is populated in lockstep with totals — name is guaranteed present.\n const top_streams = [...per_stream.get(name)!.entries()]\n .map(([stream, c]) => ({ stream, count: c }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 10);\n findings.push({\n category: \"deprecated-load\",\n name,\n current_version,\n total: count,\n top_streams,\n });\n }\n return findings;\n },\n };\n};\n\n/**\n * `close-candidate` — flags streams ripe for `app.close(...)`. Two\n * flavours: `idle` (head older than `idle_days`) and `terminal` (head\n * event name in operator-supplied `terminal_events` list). Each\n * finding carries `restart_supported` (state has `.snap()`).\n */\nconst make_close_candidate_pass: PassFactory = (deps, options) => {\n const idle_days = options.thresholds?.idle_days ?? DEFAULTS.idle_days;\n const terminal_events = new Set(options.thresholds?.terminal_events ?? []);\n const idle_cutoff = Date.now() - idle_days * 24 * 60 * 60 * 1000;\n const findings: AuditFinding[] = [];\n return {\n category: \"close-candidate\",\n on_stat(stream, { head }) {\n const head_name = String(head.name);\n if (head_name.startsWith(\"__\")) return; // already-closed or mid-truncate\n // All in-tree adapters return `created` as Date; the Date\n // constructor passes Date instances through unchanged, so a\n // single call shape works regardless.\n const head_time = head.created.getTime();\n const is_idle = head_time < idle_cutoff;\n const is_terminal = terminal_events.has(head_name);\n if (!is_idle && !is_terminal) return;\n findings.push({\n category: \"close-candidate\",\n stream,\n last_event_at: head.created.toISOString(),\n reason: is_terminal ? \"terminal\" : \"idle\",\n idle_days: is_idle\n ? Math.floor((Date.now() - head_time) / (24 * 60 * 60 * 1000))\n : undefined,\n restart_supported: restart_is_supported(deps, head_name),\n });\n },\n drain: () => findings,\n };\n};\n\n/**\n * `restart-candidate` — streams above `event_count_for_restart` whose\n * state declares `.snap()`. Reads from the shared `on_stat` stream.\n */\nconst make_restart_candidate_pass: PassFactory = (deps, options) => {\n const threshold = options.thresholds?.restart_min ?? DEFAULTS.restart_min;\n // Resolved in finalize — the shared stat scan excludes `__snapshot__`\n // (so heads and counts are domain figures), which means the snapshot\n // tally isn't in `names`. Candidates are streams above `restart_min`,\n // so this is a handful of targeted counts, not a second table walk.\n const candidates: Array<{ stream: string; count: number }> = [];\n const findings: AuditFinding[] = [];\n return {\n category: \"restart-candidate\",\n on_stat(stream, { head, count }) {\n // `count` always populated — query_stats is called with the flag set.\n if (count! < threshold) return;\n const head_name = String(head.name);\n if (head_name.startsWith(\"__\")) return;\n if (!restart_is_supported(deps, head_name)) return;\n candidates.push({ stream, count: count! });\n },\n async finalize(deps) {\n for (const { stream, count } of candidates) {\n let snaps = 0;\n await deps.store().query(\n () => {\n snaps++;\n },\n {\n stream,\n stream_exact: true,\n names: [SNAP_EVENT],\n with_snaps: true,\n }\n );\n findings.push({\n category: \"restart-candidate\",\n stream,\n count,\n snaps,\n });\n }\n },\n drain: () => findings,\n };\n};\n\n/**\n * `reaction-health` — surfaces blocked / near-block / stuck-backoff\n * streams. Reads from the shared `on_stream` stream-positions\n * broadcast.\n */\nconst make_reaction_health_pass: PassFactory = (_deps, options) => {\n const near_block = options.thresholds?.near_block ?? DEFAULTS.near_block;\n const stuck_minutes =\n options.thresholds?.stuck_minutes ?? DEFAULTS.stuck_minutes;\n const stuck_cutoff = Date.now() - stuck_minutes * 60 * 1000;\n const findings: AuditFinding[] = [];\n return {\n category: \"reaction-health\",\n on_stream(p) {\n if (p.blocked) {\n findings.push({\n category: \"reaction-health\",\n stream: p.stream,\n status: \"blocked\",\n retry: p.retry,\n reason: p.error || \"blocked without recorded error\",\n });\n return;\n }\n if (p.retry >= near_block) {\n findings.push({\n category: \"reaction-health\",\n stream: p.stream,\n status: \"near-block\",\n retry: p.retry,\n reason: `retry ${p.retry} ≥ near-block threshold ${near_block}`,\n });\n return;\n }\n if (\n p.leased_by &&\n p.leased_until &&\n p.leased_until.getTime() < stuck_cutoff\n ) {\n const minutes = Math.floor(\n (Date.now() - p.leased_until.getTime()) / (60 * 1000)\n );\n findings.push({\n category: \"reaction-health\",\n stream: p.stream,\n status: \"stuck-backoff\",\n retry: p.retry,\n reason: `lease expired ${minutes}m ago without release`,\n });\n }\n },\n drain: () => findings,\n };\n};\n\n/**\n * `snapshot-drift` — buffers candidate streams from the shared\n * `on_stat` pass (skipping non-snap states + tombstoned heads), then\n * does targeted per-stream lookups in `finalize` to find the last\n * `__snapshot__` event id and count events past it.\n */\nconst make_snapshot_drift_pass: PassFactory = (deps, options) => {\n const drift_min = options.thresholds?.drift_min ?? DEFAULTS.drift_min;\n // Streams the workspace pass identifies as drift candidates —\n // resolved in finalize with per-stream queries.\n const candidates: Array<{\n stream: string;\n total: number;\n }> = [];\n const findings: AuditFinding[] = [];\n return {\n category: \"snapshot-drift\",\n on_stat(stream, { head, count }) {\n // restart_is_supported() already filters out framework markers\n // (__snapshot__, __tombstone__) — neither name appears in any\n // user state's events map, so the snap check rejects them.\n if (!restart_is_supported(deps, String(head.name))) return;\n if (count! < drift_min) return; // upper-bound short-circuit\n candidates.push({\n stream,\n total: count!,\n });\n },\n async finalize(deps) {\n for (const { stream, total } of candidates) {\n let events_since_snap = total;\n let snap_at: number | undefined;\n // The shared stat scan excludes `__snapshot__` so every other\n // pass sees domain heads, which means the snapshot count isn't\n // in `names` — resolve it from this targeted lookup instead. A\n // stream with no snapshot yields nothing here and keeps\n // `events_since_snap = total`, the same answer as before.\n const collected: Array<{ id: number }> = [];\n await deps.store().query(\n (e) => {\n collected.push({ id: e.id });\n },\n {\n stream,\n stream_exact: true,\n names: [\"__snapshot__\"],\n backward: true,\n limit: 1,\n with_snaps: true,\n }\n );\n if (collected.length > 0) {\n snap_at = collected[0]!.id;\n let after = 0;\n await deps.store().query(\n () => {\n after++;\n },\n { stream, stream_exact: true, after: snap_at }\n );\n events_since_snap = after;\n }\n if (events_since_snap < drift_min) continue;\n findings.push({\n category: \"snapshot-drift\",\n stream,\n events_since_snap,\n snap_at,\n });\n }\n },\n drain: () => findings,\n };\n};\n\n/**\n * `routing-health` — `unknown-lane` from the streams-table pass +\n * `unrouted` from the stats pass. Reads from BOTH shared streams.\n */\nconst make_routing_health_pass: PassFactory = (deps) => {\n const findings: AuditFinding[] = [];\n const seen_event_names = new Set<string>();\n return {\n category: \"routing-health\",\n on_stream(p) {\n if (!p.lane) return; // default lane — never an unknown-lane finding\n if (deps.declared_lanes.has(p.lane)) return;\n findings.push({\n category: \"routing-health\",\n stream: p.stream,\n reason: \"unknown-lane\",\n lane: p.lane,\n });\n },\n on_stat(_stream, { names }) {\n for (const name of Object.keys(names!)) {\n seen_event_names.add(name);\n }\n },\n finalize() {\n for (const name of seen_event_names) {\n if (name.startsWith(\"__\")) continue;\n if (deps.routed_events.has(name)) continue;\n findings.push({\n category: \"routing-health\",\n stream: \"*\",\n reason: \"unrouted\",\n });\n }\n return Promise.resolve();\n },\n drain: () => findings,\n };\n};\n\n/**\n * `correlation-gaps` — collects ids + parent_ids during the shared\n * event pass; flags orphans in `drain`. No second store walk — the\n * id-set + the (id, parent) buffer are both populated in one pass.\n */\nconst make_correlation_gaps_pass: PassFactory = () => {\n const seen_ids = new Set<number>();\n const checks: Array<{ stream: string; id: number; parent_id: number }> = [];\n return {\n category: \"correlation-gaps\",\n on_event(e) {\n seen_ids.add(e.id);\n const causation = (e.meta as Record<string, unknown> | undefined)\n ?.causation as { event?: { id?: number } } | undefined;\n const parent_id = causation?.event?.id;\n if (parent_id !== undefined) {\n checks.push({ stream: e.stream, id: e.id, parent_id });\n }\n },\n drain() {\n const findings: AuditFinding[] = [];\n for (const { stream, id, parent_id } of checks) {\n if (!seen_ids.has(parent_id)) {\n findings.push({\n category: \"correlation-gaps\",\n stream,\n event_id: id,\n reason: \"orphan-parent\",\n });\n }\n }\n return findings;\n },\n };\n};\n\n/**\n * `clock-anomalies` — flags future timestamps + per-stream out-of-\n * order `created`. Single pass, per-stream \"last seen\" state in a\n * Map. Cheap.\n */\nconst make_clock_anomalies_pass: PassFactory = () => {\n const findings: AuditFinding[] = [];\n const last_per_stream = new Map<string, number>();\n return {\n category: \"clock-anomalies\",\n on_event(e) {\n // `created` is a Date instance per the Store contract.\n const created = e.created.getTime();\n if (created > Date.now()) {\n findings.push({\n category: \"clock-anomalies\",\n stream: e.stream,\n event_id: e.id,\n reason: \"future-created\",\n });\n }\n const prev = last_per_stream.get(e.stream);\n if (prev !== undefined && created < prev) {\n findings.push({\n category: \"clock-anomalies\",\n stream: e.stream,\n event_id: e.id,\n reason: \"out-of-order\",\n });\n }\n last_per_stream.set(e.stream, created);\n },\n drain: () => findings,\n };\n};\n\n/** Does the stream's owning state declare a `.snap()` reducer? */\nfunction restart_is_supported(\n deps: AuditDeps,\n head_event_name: string\n): boolean {\n const state = deps.event_to_state.get(head_event_name);\n return state?.snap !== undefined;\n}\n\n/** Factory registry — pass-creation indexed by category name. */\nconst PASS_FACTORIES: Record<AuditCategory, PassFactory> = {\n schema: make_schema_pass,\n \"deprecated-load\": make_deprecated_load_pass,\n \"close-candidate\": make_close_candidate_pass,\n \"restart-candidate\": make_restart_candidate_pass,\n \"reaction-health\": make_reaction_health_pass,\n \"snapshot-drift\": make_snapshot_drift_pass,\n \"routing-health\": make_routing_health_pass,\n \"correlation-gaps\": make_correlation_gaps_pass,\n \"clock-anomalies\": make_clock_anomalies_pass,\n};\n","/**\n * @module autoclose-policy\n * @category Internal\n *\n * Declarative close-policy options consumed by `.autocloses({...})`\n * (#838 / epic #802). Three optional fields cover the three\n * operational pressure points every real close policy traces back to:\n *\n * - `after` — time / compliance (\"autocloses **after** N days\")\n * - `is` — domain lifecycle (\"autocloses ... **is** Resolved\")\n * - `reaches` — resource (\"autocloses ... **reaches** 10k events\")\n *\n * Top-level fields combine with **AND** semantics. This captures the\n * common cooldown-after-terminal pattern that runs through almost\n * every business app — *\"close 90 days after `Resolved`\"*, *\"close 14\n * days after `Delivered`\"*, *\"close 30 days after a GDPR deletion\n * request\"*. All conditions must hold for the cycle to truncate.\n *\n * A separate `or: {...}` block opens an alternative path: when\n * present, the policy fires if **either** the top-level AND group\n * matches **or** any field inside `or` matches. Use it for safety\n * nets — *\"close (Resolved AND aged 90 days) OR if event count\n * reaches 10k\"*. The two-axis split mirrors the two ways close\n * policies appear in practice: primary close logic (AND-shaped) and\n * defensive backstops (OR-shaped).\n *\n * The state builder's `.autocloses(...)` overload distinguishes\n * function (predicate) from object (policy) and routes the latter\n * through {@link compile_autoclose_policy}, which validates via\n * {@link AutoclosePolicySchema} and returns the compiled predicate.\n * Operators with custom needs (per-stream metadata, multi-branch\n * AND/OR like \"(`Resolved` + 90d) OR (`Cancelled` + 30d)\") keep the\n * function form; the declarative form covers the 90% case.\n *\n * Validation runs at the builder call (`act().build()` time), so\n * misconfiguration — empty bag, sub-1 `reaches`, sub-minute `after`,\n * empty `is`, empty `or`, nested `or` inside `or`, unknown keys —\n * throws at build, not on the first cycle tick.\n *\n * @internal\n */\n\nimport { z } from \"zod\";\nimport type { AutoclosePredicate, Schemas } from \"../types/action.js\";\n\n/**\n * One day in epoch milliseconds. The close surface is day-denominated\n * throughout — policies declare `{ days }`, the State carries\n * `autoclose_*_days`, and the reaction thinks in day offsets. This\n * constant (with {@link days_after} / {@link days_before_now}) is the\n * single place the closing process touches epoch arithmetic, because\n * `Date` itself has no other currency.\n */\nconst DAY_MS = 86_400_000;\n\n/**\n * Lower bound on a resolved `after` window: one minute, expressed in\n * days. Sub-minute cooldowns are almost always misconfiguration.\n * Rejecting at build keeps the failure mode noisy.\n */\nconst MIN_AFTER_DAYS = 1 / 1440;\n\n/**\n * Lower bound on a resolved `keep` window: one full day. The close\n * cycle is low-cadence, non-priority housekeeping — a rolling window\n * shorter than a day signals misconfiguration. Real retention\n * contracts (180 days, 7 years) are days and up.\n */\nconst MIN_KEEP_DAYS = 1;\n\n/** The `Date` that lies `days` after `date`. @internal */\nexport function days_after(date: Date, days: number): Date {\n return new Date(date.getTime() + days * DAY_MS);\n}\n\n/** The `Date` that lies `days` in the past. @internal */\nexport function days_before_now(days: number): Date {\n return new Date(Date.now() - days * DAY_MS);\n}\n\n/**\n * Day-denominated window shared by `after` (terminate cooldown) and\n * `keep` (rolling retention). Fractional days accepted; windows below\n * the field's floor reject at build.\n *\n * @internal\n */\nconst window_schema = (\n field: \"after\" | \"keep\",\n min_days: number,\n floor: string\n) =>\n z\n .object({\n days: z\n .number({ message: `autocloses: ${field}.days must be a number` })\n .positive(`autocloses: ${field}.days must be > 0`),\n })\n .refine((o) => o.days >= min_days, {\n message: `autocloses: ${field} resolves to < ${floor}, which is too short to be a meaningful retention window`,\n });\n\nconst AfterSchema = window_schema(\"after\", MIN_AFTER_DAYS, \"one minute\");\n\nconst KeepSchema = window_schema(\"keep\", MIN_KEEP_DAYS, \"one day\");\n\nconst IsSchema = z.union([\n z.string().min(1, \"autocloses: is must be a non-empty event name\"),\n z\n .array(\n z.string().min(1, \"autocloses: is entries must be non-empty event names\")\n )\n .min(1, \"autocloses: is must include at least one event name\")\n .readonly(),\n]);\n\nconst ReachesSchema = z\n .number({ message: \"autocloses: reaches must be a number\" })\n .int(\"autocloses: reaches must be an integer\")\n .min(1, \"autocloses: reaches must be >= 1\");\n\n/**\n * Schema for the `or: {...}` block — the OR-shaped alternative path.\n * Same field set as the top-level policy minus `or` itself (so nested\n * `or` inside `or` rejects via `.strict()` instead of recursing). At\n * least one field required; empty `{}` is a misconfiguration.\n *\n * @internal\n */\nconst OrBlockSchema = z\n .object({\n after: AfterSchema.optional(),\n is: IsSchema.optional(),\n reaches: ReachesSchema.optional(),\n })\n .strict()\n .refine(\n (o) =>\n o.after !== undefined || o.is !== undefined || o.reaches !== undefined,\n {\n message:\n \"autocloses: `or` block must include at least one of after / is / reaches\",\n }\n );\n\n/**\n * Zod schema for the declarative {@link AutoclosePolicy} bag.\n * Internal `const` per the config-validation-schema standard (CLAUDE.md\n * \"Config-validation schemas\") — the public surface is the inferred\n * {@link AutoclosePolicy} type and the `.autocloses({...})` overload,\n * never this schema. `.strict()` rejects unknown keys so typos surface\n * at build instead of being silently ignored.\n *\n * @internal\n */\nconst AutoclosePolicySchema = z\n .object({\n after: AfterSchema.optional(),\n is: IsSchema.optional(),\n reaches: ReachesSchema.optional(),\n or: OrBlockSchema.optional(),\n keep: KeepSchema.optional(),\n })\n .strict()\n .refine(\n (o) =>\n o.after !== undefined ||\n o.is !== undefined ||\n o.reaches !== undefined ||\n o.or !== undefined ||\n o.keep !== undefined,\n {\n message:\n \"autocloses: at least one of after / is / reaches / or / keep must be specified — empty `{}` is a misconfiguration\",\n }\n );\n\n/**\n * Declarative close-policy options consumed by `.autocloses({...})`.\n * Top-level fields are AND-combined; the optional `or` block opens an\n * alternative OR-path. Omitted fields contribute nothing — they do\n * not mean \"match everything.\"\n *\n * @property after - Close when `head.created` is at least the resolved\n * window in the past. Days are the close surface's only unit;\n * fractional `days` cover sub-day cooldowns (`{ days: 1/24 }` is one\n * hour) without introducing another denomination.\n * @property is - Close when `head.name` matches. String for the\n * single-terminal-event case (the most common); `readonly string[]`\n * for multi-terminal states (`Order: Shipped | Delivered |\n * Cancelled`).\n * @property reaches - Close when the stream's event count is `>= N`\n * (inclusive — fires the moment the threshold is reached).\n * @property or - Alternative OR-path. When present, the policy fires\n * if EITHER the top-level AND group matches OR any field inside\n * `or` matches. Used for safety-net backstops layered onto a\n * primary cooldown policy (e.g. *\"(Resolved AND 90 days) OR reaches\n * 10k\"*). Nested `or` inside `or` rejects at build time.\n * @property keep - Rolling-window retention (#1011), **independent** of\n * the terminate fields: while the stream stays open, prune events\n * older than `now − keep` behind the closest safe snapshot via a\n * windowed close. Does not participate in the AND group or the `or`\n * block — a policy may terminate, prune, or both. Requires\n * `.snap(...)` earlier in the builder chain (type-gated) and a\n * window of at least one day — the close cycle is low-cadence\n * housekeeping, never sub-day realtime.\n */\nexport type AutoclosePolicy = z.infer<typeof AutoclosePolicySchema>;\n\n/** Compile a single `after` field into its predicate slice. @internal */\nfunction compile_after(\n after: NonNullable<AutoclosePolicy[\"after\"]>\n): AutoclosePredicate<Schemas> {\n return (_stream, head) => days_after(head.created, after.days) <= new Date();\n}\n\n/** Compile a single `is` field into its predicate slice. @internal */\nfunction compile_is(\n is: NonNullable<AutoclosePolicy[\"is\"]>\n): AutoclosePredicate<Schemas> {\n const set = new Set(typeof is === \"string\" ? [is] : is);\n return (_stream, head) => set.has(head.name as string);\n}\n\n/** Compile a single `reaches` field into its predicate slice. @internal */\nfunction compile_reaches(\n reaches: NonNullable<AutoclosePolicy[\"reaches\"]>\n): AutoclosePredicate<Schemas> {\n return (_stream, _head, count) => count >= reaches;\n}\n\n/**\n * Compile a declarative {@link AutoclosePolicy} into an\n * {@link AutoclosePredicate}. The state-builder's\n * `.autocloses({...})` overload calls this; tests can also build a\n * state and read `state.autoclose` to grab the compiled predicate.\n *\n * Returned predicate fires when either:\n *\n * 1. **All** top-level non-`or` fields match (AND), or\n * 2. **Any** field inside the `or` block matches.\n *\n * Top-level with zero non-`or` fields never satisfies path (1) — the\n * `every` check on an empty list is short-circuited to `false` so the\n * policy doesn't truncate the entire universe on an `or`-only\n * declaration. (Validation rejects all-empty bags up front; this guard\n * is the in-cycle equivalent for the synthesized empty AND-group.)\n *\n * Assignable to any `AutoclosePredicate<TEvents>` slot via\n * function-parameter contravariance — the returned predicate inspects\n * `head.name` as a plain string, so narrower event unions stay\n * assignable.\n *\n * Throws `ZodError` at call time when the options are invalid (empty\n * bag, non-positive `reaches`, sub-minute `after`, empty `is`, empty\n * `or`, nested `or`, unknown keys).\n *\n * @internal\n */\n/**\n * The smallest `after` window (in days) anywhere in a policy — across\n * the top-level `after` and the `or.after` block — or `undefined` when\n * the policy has no time component.\n *\n * The synthesized autoclose reaction (#1090) uses this to decide how to\n * wait: a policy with an `after` defers its re-check to `head.created`\n * plus this many days (the earliest its time gate could open); a policy\n * without one (`is` / `reaches` only) has no time gate, so the reaction\n * just waits for the next event to re-trigger rather than parking on a\n * due-time. Conservative — the min across branches never defers past\n * the soonest a branch could fire.\n *\n * @internal\n */\nexport function policy_min_after_days(\n options: AutoclosePolicy\n): number | undefined {\n const parsed = AutoclosePolicySchema.parse(options);\n const windows: number[] = [];\n if (parsed.after) windows.push(parsed.after.days);\n if (parsed.or?.after) windows.push(parsed.or.after.days);\n return windows.length ? Math.min(...windows) : undefined;\n}\n\n/**\n * The rolling-window width (in days) of a policy's `keep` field, or\n * `undefined` when the policy declares no rolling window. The\n * synthesized autoclose reaction prunes the prefix older than the\n * window (via a windowed close) and derives its prune due-time as\n * `tail.created` plus this many days — the earliest the oldest\n * surviving domain event can age out of the window.\n *\n * @internal\n */\nexport function policy_keep_days(options: AutoclosePolicy): number | undefined {\n const parsed = AutoclosePolicySchema.parse(options);\n return parsed.keep?.days;\n}\n\nexport function compile_autoclose_policy(\n options: AutoclosePolicy\n): AutoclosePredicate<Schemas> {\n const parsed = AutoclosePolicySchema.parse(options);\n\n // Top-level AND group — only the non-`or` fields.\n const and_preds: AutoclosePredicate<Schemas>[] = [];\n if (parsed.after) and_preds.push(compile_after(parsed.after));\n if (parsed.is) and_preds.push(compile_is(parsed.is));\n if (parsed.reaches) and_preds.push(compile_reaches(parsed.reaches));\n\n // OR-block — at least one of its fields must match.\n const or_preds: AutoclosePredicate<Schemas>[] = [];\n if (parsed.or) {\n if (parsed.or.after) or_preds.push(compile_after(parsed.or.after));\n if (parsed.or.is) or_preds.push(compile_is(parsed.or.is));\n if (parsed.or.reaches) or_preds.push(compile_reaches(parsed.or.reaches));\n }\n\n return (stream, head, count) => {\n // AND path: every top-level field matches AND the group is non-empty\n // (an `or`-only declaration leaves `and_preds` empty — that\n // shouldn't auto-fire).\n if (\n and_preds.length > 0 &&\n and_preds.every((p) => p(stream, head, count))\n ) {\n return true;\n }\n // OR path: any `or`-block field matches.\n if (or_preds.some((p) => p(stream, head, count))) {\n return true;\n }\n return false;\n };\n}\n","/**\n * @module autoclose-window\n * @category Internal\n *\n * Off-hours window math for autoclose — hour-in-zone, DST-gap handling, and\n * \"next time the window opens\". The autoclose **config** (defaults, schema,\n * resolver) lives in `./config.js`, the single home for builder-facing config\n * bags; this module is the runtime window logic those knobs drive.\n *\n * @internal\n */\n\nimport type { AutocloseConfig } from \"./config.js\";\n\n/**\n * The current hour `[0, 23]` in the given IANA time zone, DST-correct\n * via `Intl`. Split out so the window check can be unit-tested without\n * spinning a controller.\n *\n * @internal\n */\nexport function hour_in_zone(now: Date, timeZone: string): number {\n const parts = new Intl.DateTimeFormat(\"en-US\", {\n timeZone,\n hour: \"2-digit\",\n hourCycle: \"h23\",\n }).formatToParts(now);\n return Number(parts.find((p) => p.type === \"hour\")?.value);\n}\n\n/**\n * True when a plain `[start, end)` hour comparison places `hour` inside\n * the window. Half-open on hour boundaries and wrapping past midnight\n * when `start > end`.\n *\n * @internal\n */\nfunction hour_in_range(hour: number, start: number, end: number): boolean {\n return start < end\n ? hour >= start && hour < end\n : hour >= start || hour < end;\n}\n\n/**\n * True when `now` is the instant a DST spring-forward gap skipped over\n * the window's `start` hour. On such a day the local `start` hour never\n * occurs — the clock jumps from `start - 1` straight past `start` — so a\n * plain hour comparison would report the window closed all day. The gap\n * surfaces as a one-hour boundary where the local hour jumps from below\n * `start` to above it; that boundary instant is the window's replacement\n * opening. Detected by comparing the hour at `now` with the hour one\n * hour earlier: a jump of more than one hour that steps over `start`.\n *\n * @internal\n */\nfunction is_dst_gap_open(now: Date, timeZone: string, start: number): boolean {\n const hour = hour_in_zone(now, timeZone);\n if (hour <= start) return false;\n const prev = hour_in_zone(new Date(now.getTime() - 3_600_000), timeZone);\n // A normal step advances one local hour; a spring-forward gap advances\n // two, skipping exactly one local hour. This instant is the gap opening\n // only when the skipped hour is the window's `start`: the previous hour\n // sits just below `start` and this hour just above it.\n return prev === start - 1 && hour === start + 1;\n}\n\n/**\n * Whether `now` falls inside the configured off-hours window. The\n * window is half-open on hour boundaries — `[start, end)` — and wraps\n * past midnight when `start > end`. With no window configured every\n * tick runs, so callers treat `undefined` as \"always in window.\"\n *\n * On a DST spring-forward day whose `start` hour is skipped, the window\n * would otherwise be closed for the whole day (the `start` hour never\n * occurs). The gap's replacement instant is admitted so autoclose still\n * runs — see {@link is_dst_gap_open}.\n *\n * @internal\n */\nexport function in_autoclose_window(\n window: AutocloseConfig[\"autocloseWindow\"],\n now: Date\n): boolean {\n if (!window) return true;\n const hour = hour_in_zone(now, window.timeZone);\n return (\n hour_in_range(hour, window.start, window.end) ||\n is_dst_gap_open(now, window.timeZone, window.start)\n );\n}\n\n/**\n * The next instant the off-hours window opens at or after `now`. The\n * synthesized autoclose reaction defers to this when a tick lands\n * outside the window — parking until the window actually opens instead\n * of blind-polling on a configured cadence (the pre-#1175 behavior,\n * where a poll interval longer than the window could oscillate around\n * it and miss it repeatedly).\n *\n * Walks forward hour by hour and asks `Intl` for the local hour at each\n * step, so DST transitions resolve exactly the way the runtime's zone\n * database says they do — a 23- or 25-hour day never desynchronizes the\n * walk. The window validates as non-empty at build, and every zone hits\n * each `[0, 23]` hour label within any 48-hour span, so the walk always\n * terminates; the bound is a defensive backstop, with \"one day out\" as\n * the fallback no real zone can reach.\n *\n * Minute/second offsets within the opening hour are preserved from\n * `now` shifted by whole hours — the contract is hour-granular, matching\n * the window's own `[start, end)` hour semantics.\n *\n * On a DST spring-forward day whose `start` hour is skipped, the `start`\n * hour never occurs, so the minute-preserving walk would never match and\n * the window would defer ~24 h. The walk also checks each hour-aligned\n * boundary for the gap opening (see {@link is_dst_gap_open}) and returns\n * that boundary instant — deferring ~1 h to the replacement instant\n * rather than a full day. The boundary is returned as-is (no minute\n * offset): the gap opening is a single transition instant, not a range.\n *\n * @internal\n */\nexport function next_window_open(\n window: NonNullable<AutocloseConfig[\"autocloseWindow\"]>,\n now: Date\n): Date {\n const start_ms = now.getTime();\n for (let h = 0; h <= 48; h++) {\n const candidate = new Date(start_ms + h * 3_600_000);\n if (hour_in_zone(candidate, window.timeZone) === window.start)\n return candidate;\n // The `start` hour may be unreachable on a spring-forward day; catch\n // the gap boundary at the top of this candidate's hour.\n const boundary = new Date(\n candidate.getTime() - (candidate.getTime() % 3_600_000)\n );\n if (is_dst_gap_open(boundary, window.timeZone, window.start))\n return boundary;\n }\n return new Date(start_ms + 86_400_000);\n}\n","/**\n * @module close-signal\n * @category Internal\n *\n * The control-flow signal a reaction handler throws to *close* a stream\n * (#1090). Like {@link \"defer-signal\".DeferSignal} it rides the dispatcher's\n * `try/catch`, but where a defer holds the stream for later, a close asks the\n * orchestrator to retire it: `build_handle` turns the signal into a\n * `HandleResult.close` (a {@link CloseTarget}), `run_drain_cycle` acks the\n * triggering event and collects the target, and the `DrainController` hands it\n * to the orchestrator's `on_close` callback, which runs the same\n * `run_close_cycle` machinery as `app.close`.\n *\n * Internal: the compiled autoclose reaction throws it. Closing stays an\n * orchestrator capability — reactions only *signal* the intent, so the public\n * reaction-scoped `IAct` gains no `close`.\n *\n * The autoclose reaction runs on a **synthetic stream** (`source` = the\n * aggregate, `target` = a per-aggregate `__autoclose__` key) so it never\n * shares a watermark with the aggregate's own reactions. That makes the close\n * *target* distinct from the reaction's lease stream, so the signal carries the\n * stream to close explicitly (`stream`); when omitted (a user reaction closing\n * its own stream) it defaults to the lease stream.\n *\n * @internal\n */\nexport class CloseSignal extends Error {\n /**\n * Stream to close. Omitted → the reaction's own lease stream (a self-close).\n * The synthesized autoclose reaction sets it to the aggregate stream, since\n * its lease runs on a synthetic `__autoclose__` target.\n */\n readonly stream?: string;\n /** Optional archive callback to run while the stream is guarded. */\n readonly archive?: () => Promise<void>;\n /**\n * Watermark to ack the requesting reaction to before the close runs. The\n * close-cycle safety guard skips a stream whose subscriptions (matched by\n * source) lag the head; the autoclose reaction's `source` is the aggregate,\n * so it must advance its own watermark to the live head id it evaluated\n * against — otherwise it blocks its own close. Defaults to the triggering\n * event id when omitted.\n */\n readonly at?: number;\n /**\n * Windowed close (#1011): prune events older than this cutoff behind\n * the closest safe snapshot instead of retiring the stream. Thrown by\n * the autoclose reaction of a `.autocloses({ keep })` state; flows\n * into {@link CloseTarget.before}. Omitted → a full close.\n */\n readonly before?: Date;\n\n constructor(opts?: {\n stream?: string;\n archive?: () => Promise<void>;\n at?: number;\n before?: Date;\n }) {\n super(\"reaction requested close\");\n this.name = \"CloseSignal\";\n this.stream = opts?.stream;\n this.archive = opts?.archive;\n this.at = opts?.at;\n this.before = opts?.before;\n }\n}\n","/**\n * @module defer-signal\n * @category Internal\n *\n * The control-flow signal a reaction handler throws to *defer* itself\n * (#1090, #1091). Unlike an error, a defer is not a failure: the dispatcher\n * ({@link \"reactions\".build_handle}) catches it and produces a\n * `HandleResult.defer` — the triggering events stay pending (watermark not\n * advanced), `retry` is not bumped, and the drain re-visits the stream at the\n * resolved due-time.\n *\n * `DeferSignal` is the **imperative escape hatch** and is re-exported from the\n * package root, so reaction code can throw it directly when a static\n * `.defer(when)` step isn't expressive enough (a deadline computed from loaded\n * state, say). It carries the *unresolved* {@link DeferWhen}; the dispatcher\n * resolves it against the triggering event it is already dispatching (via\n * `resolve_defer_at`), which is what anchors `{ after }` and the `at` function\n * form to that event and keeps the due-time derivable. Fully dynamic times go\n * through `{ at: someDate }`.\n *\n * Modeled as an `Error` subclass — like `NonRetryableError` — so it rides the\n * existing `try/catch` in the handler loop instead of needing a separate\n * return channel through every dispatcher signature. The compiled autoclose\n * reaction throws the same signal.\n */\nimport type { DeferWhen } from \"../types/index.js\";\n\nexport class DeferSignal extends Error {\n /**\n * The unresolved schedule. The dispatcher turns this into an absolute\n * due-time by resolving it against the triggering event.\n */\n readonly when: DeferWhen;\n\n constructor(when: DeferWhen) {\n super(\"reaction deferred\");\n this.name = \"DeferSignal\";\n this.when = when;\n }\n}\n","/**\n * @module autoclose-reaction\n * @category Internal\n *\n * Synthesis of the online close-the-books reaction. `.autocloses(policy)`\n * is not a sweep: it is a reaction on every event the declaring state owns\n * that evaluates the policy against the LIVE head (so a reopened stream\n * re-evaluates correctly), defers to the cooldown's earliest opening\n * (`head.created + the policy's min after`), and closes via `CloseSignal`\n * once the policy holds.\n *\n * Runs at build time — after the registry is fully merged and before the\n * orchestrator classifies it — so the synthesized dynamic resolver is\n * discovered by `classify_registry` and its target stream subscribed. The\n * registry is complete once the builder finishes; the orchestrator never\n * mutates it.\n *\n * @internal\n */\n\nimport { SNAP_EVENT, store, TOMBSTONE_EVENT } from \"../ports.js\";\nimport type {\n Reaction,\n Registry,\n SchemaRegister,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport { days_after, days_before_now } from \"./autoclose-policy.js\";\nimport { in_autoclose_window, next_window_open } from \"./autoclose-window.js\";\nimport { CloseSignal } from \"./close-signal.js\";\nimport type { AutocloseConfig } from \"./config.js\";\nimport { DeferSignal } from \"./defer-signal.js\";\n\n/**\n * Prefix for the synthetic per-aggregate stream the autoclose reaction\n * runs on. `target = \\`${AUTOCLOSE_TARGET_PREFIX}${aggregate}\\``, `source =\n * aggregate` — a watermark distinct from the aggregate's own reactions, so\n * an autoclose defer never short-circuits them. Internal; not a public\n * surface.\n */\nexport const AUTOCLOSE_TARGET_PREFIX = \"__autoclose__:\";\n\n/**\n * Inject one synthesized autoclose reaction per `.autocloses(...)` state\n * into the registry's event registers. The handler resolves ports at call\n * time (`store()`), so the reaction is orchestrator-agnostic; the resolved\n * window/cadence config is captured here, at build.\n *\n * @internal\n */\nexport function synthesize_autoclose_reactions<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n registry: Registry<TSchemaReg, TEvents, TActions>,\n states: ReadonlyMap<string, State<any, any, any>>,\n config: AutocloseConfig\n): void {\n for (const st of states.values()) {\n const predicate = st.autoclose;\n if (!predicate) continue;\n const after_days = st.autoclose_after_days;\n const keep_days = st.autoclose_keep_days;\n const archiver = st.archive;\n const reaction: Reaction<TEvents> = {\n // Run on a SYNTHETIC stream — `source` is the aggregate, `target` is a\n // per-aggregate `__autoclose__` key — so the autoclose reaction never\n // shares a watermark with the aggregate's own reactions. A shared\n // watermark would let autoclose's defer short-circuit the aggregate's\n // other reactions (the \"a defer affects all reactions on a stream\"\n // hazard). The close still targets the aggregate (`source`).\n resolver: (e) => ({\n target: `${AUTOCLOSE_TARGET_PREFIX}${e.stream}`,\n source: e.stream,\n }),\n // Never block on autoclose: a transient query/store error should retry,\n // not quarantine the synthetic stream.\n options: { blockOnError: false, maxRetries: 3 },\n handler: async (event) => {\n const aggregate = event.stream;\n // Off-hours gating: outside the window, park until the window\n // opens. Derived from the window itself — no polling cadence.\n if (!in_autoclose_window(config.autocloseWindow, new Date()))\n throw new DeferSignal({\n at: next_window_open(config.autocloseWindow!, new Date()),\n });\n // Every policy keys on the *domain* head/count, so snapshots are\n // excluded unconditionally (#1356) — matching `scan_stream_heads` in\n // close-cycle.ts. `snap()` commits a `__snapshot__` at a higher id\n // right after the triggering domain event, so a terminal commit that\n // crosses a `.snap()` boundary would otherwise make the snapshot the\n // head: `is` never matches (`head.name === \"__snapshot__\"`) and never\n // recovers, `after` measures the cooldown from the snapshot's\n // timestamp, and `reaches:N` counts snapshot events toward N. Only\n // rolling-window (`keep`) policies additionally fetch the tail: the\n // prune decision keys on the oldest *domain* event — after a prune the\n // oldest surviving event is the boundary snapshot, whose age says\n // nothing about whether another prune would be productive.\n const stats = await store().query_stats([aggregate], {\n count: true,\n tail: keep_days !== undefined ? true : undefined,\n exclude: [TOMBSTONE_EVENT, SNAP_EVENT],\n });\n const entry = stats.get(aggregate);\n // No live (non-tombstone) head → already closed, nothing to do.\n if (!entry) return;\n const head = entry.head;\n // `count` is always present — query_stats is called with\n // `count: true` above, so the option contract guarantees it.\n if (predicate(aggregate, head, entry.count!))\n throw new CloseSignal({\n stream: aggregate,\n archive: archiver ? () => archiver(aggregate, head) : undefined,\n // Ack this reaction's own watermark to the live head so the\n // close-cycle guard (which matches subscriptions by source =\n // aggregate) sees it caught up instead of blocking its own close.\n at: head.id,\n });\n // Rolling window: when the oldest domain event has aged out of the\n // window, stage a windowed close — prune the prefix older than the\n // cutoff behind the closest safe snapshot. `tail` is present\n // whenever the stats entry is (same non-excluded event set).\n if (keep_days !== undefined) {\n const cutoff = days_before_now(keep_days);\n if (entry.tail!.created < cutoff)\n throw new CloseSignal({\n stream: aggregate,\n before: cutoff,\n archive: archiver\n ? () => archiver(aggregate, head, cutoff)\n : undefined,\n at: head.id,\n });\n }\n // Not eligible yet: park on the earliest derivable due-time — the\n // day the terminate cooldown opens and/or the day the oldest\n // domain event ages out of the rolling window. Neither → wait for\n // the next event to re-trigger (e.g. a `reaches` threshold).\n const dues: Date[] = [];\n if (after_days !== undefined)\n dues.push(days_after(head.created, after_days));\n if (keep_days !== undefined)\n dues.push(days_after(entry.tail!.created, keep_days));\n // Only defer to a FUTURE due-time. A due already in the past (the\n // stream idled longer than the cooldown while the AND-combined\n // predicate stayed unmet) can never be excluded by `claim`, which\n // skips only future `deferred_at` — so a past defer would be\n // re-claimed every cycle (perpetual query_stats burn, #1330). When\n // nothing is future, fall through and return: advance the watermark\n // and wait for the next event to re-trigger.\n const future = dues\n .map((d) => d.getTime())\n .filter((t) => t > Date.now());\n if (future.length)\n throw new DeferSignal({ at: new Date(Math.min(...future)) });\n },\n };\n const key = `__autoclose_${st.name}`;\n for (const event_name of Object.keys(st.events)) {\n registry.events[event_name as keyof TEvents]?.reactions.set(\n key,\n reaction as Reaction<TEvents, keyof TEvents>\n );\n }\n }\n}\n","/**\n * @module build-classify\n * @category Internal\n *\n * Build-time classification of the registry + state map. The Act constructor\n * needs four pre-computed inputs to wire its runtime subsystems:\n *\n * - `static_targets` — known-up-front reaction targets (statics get\n * subscribed once at init; dynamics scan per event)\n * - `has_dynamic_resolvers` — short-circuit flag for `correlate()`\n * - `reactive_events` — event names with at least one reaction (drives\n * the drain skip-flag in `do()` and `reset()`)\n * - `event_to_state` — event-name → owning state, for `close({restart})`\n * seed loading in multi-state apps\n *\n * Pure function — single pass over events + states, fully testable without\n * instantiating Act.\n *\n * @internal\n */\n\nimport type {\n Registry,\n Schema,\n SchemaRegister,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport type { StaticTarget } from \"./correlate-cycle.js\";\n\n/**\n * Classification result. Returned by {@link classify_registry}; consumed\n * piecewise by Act's constructor.\n *\n * @internal\n */\n/**\n * Sentinel for \"any reaction on this event has a dynamic resolver, so\n * the lane is opaque until correlate runs the function — arm every\n * controller.\" A Symbol rather than a string literal so it can't\n * collide with a user-declared lane named `\"all\"`.\n *\n * @internal\n */\nexport const ALL_LANES: unique symbol = Symbol(\"act-1103/all-lanes\");\n\n/**\n * Per-event lane fan-in (ACT-1103). For events whose every reaction\n * has a static resolver, the value is the union of those reactions'\n * declared lanes — `do()` arms only those controllers on commit. For\n * events with at least one dynamic resolver, the value is\n * {@link ALL_LANES}; `do()` falls back to arming every controller.\n *\n * @internal\n */\nexport type EventLaneSet = ReadonlySet<string> | typeof ALL_LANES;\n\nexport type Classification = {\n readonly static_targets: StaticTarget[];\n readonly has_dynamic_resolvers: boolean;\n readonly reactive_events: ReadonlySet<string>;\n readonly event_to_state: ReadonlyMap<string, State<any, any, any>>;\n readonly event_to_lanes: ReadonlyMap<string, EventLaneSet>;\n};\n\n/**\n * Walk the registry once to collect static reaction targets, the dynamic-\n * resolvers flag, the set of reactive event names, and the event-to-state\n * map. Static targets are deduplicated by (target, source) — two reactions\n * routing to the same projection produce one subscription.\n *\n * @internal\n */\nexport function classify_registry<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n registry: Registry<TSchemaReg, TEvents, TActions>,\n states: ReadonlyMap<string, State<Schema, any, any>>\n): Classification {\n const statics = new Map<string, StaticTarget>();\n // Per-target lane, checked across EVERY reaction to a target regardless of\n // source (#1325). A stream drains on exactly one lane, and `subscribe`\n // keys lane per-target with last-writer-wins semantics, so lane must agree\n // target-wide — the `(target, source)` scoping of `statics` is too narrow\n // to catch a same-target/different-source lane disagreement.\n const target_lanes = new Map<string, string | undefined>();\n const reactive_events = new Set<string>();\n const event_to_lanes = new Map<string, EventLaneSet>();\n let has_dynamic_resolvers = false;\n\n for (const [name, register] of Object.entries(registry.events)) {\n if (register.reactions.size > 0) reactive_events.add(name);\n for (const reaction of register.reactions.values()) {\n if (typeof reaction.resolver === \"function\") {\n has_dynamic_resolvers = true;\n // Dynamic resolver — lane is opaque until runtime. Mark the\n // event as wildcard so `do()` falls back to arming every\n // controller for any commit of it.\n event_to_lanes.set(name, ALL_LANES);\n } else {\n const { target, source, priority = 0, lane } = reaction.resolver;\n const lane_name = lane ?? \"default\";\n const existing_lanes = event_to_lanes.get(name);\n if (existing_lanes !== ALL_LANES) {\n const set =\n (existing_lanes as Set<string> | undefined) ?? new Set<string>();\n set.add(lane_name);\n event_to_lanes.set(name, set);\n }\n // ACT-1103 / #1325: lanes don't merge — any two reactions to the\n // same target must declare the same lane, regardless of source.\n // First reaction to a target records its lane; every later one must\n // match or it's a config error caught at build time.\n if (!target_lanes.has(target)) {\n target_lanes.set(target, lane);\n } else if (\n (target_lanes.get(target) ?? undefined) !== (lane ?? undefined)\n ) {\n throw new Error(\n `Stream \"${target}\" has conflicting lane assignments ` +\n `(\"${target_lanes.get(target) ?? \"default\"}\" vs \"${lane ?? \"default\"}\")`\n );\n }\n const key = `${target}|${source ?? \"\"}`;\n const existing = statics.get(key);\n if (!existing) {\n statics.set(key, { stream: target, source, priority, lane });\n } else if (priority > (existing.priority as number)) {\n // Multiple reactions with the same (target, source) — keep the max\n // priority so the highest-priority registrant sets the scheduling\n // priority (mirrors subscribe-side semantics). `existing.priority`\n // is always defined here since we always set it when inserting, but\n // the StaticTarget type marks it optional for external consumers.\n statics.set(key, { ...existing, priority });\n }\n }\n }\n }\n\n // Event-name → owning state. Duplicate event names are rejected at\n // registration time (merge.ts), so each entry is unambiguous.\n const event_to_state = new Map<string, State<any, any, any>>();\n for (const merged of states.values()) {\n for (const event_name of Object.keys(merged.events)) {\n event_to_state.set(event_name, merged);\n }\n }\n\n return {\n static_targets: [...statics.values()],\n has_dynamic_resolvers,\n reactive_events,\n event_to_state,\n event_to_lanes,\n };\n}\n","/**\n * @module internal/config\n * @category Internal\n *\n * **The single home for every builder-facing config bag in act-core.** Any\n * options object an operator hands to `act().build()`, a builder method\n * (`.on(...)`, `.do(...)`, `.withLane(...)`), or a runtime cycle\n * (`drain(...)` / `settle(...)`) is validated here with Zod — never with a\n * hand-written `if (x < min) throw` ladder — so misconfiguration surfaces as\n * a `ZodError` at the entry point, not as `NaN` arithmetic on the first cycle\n * tick.\n *\n * Layout: one section per bag, each with its `DEFAULT_*` constants, an\n * internal `<Type>OptionsSchema`, an inferred `<Type>Config`, and a\n * `resolve<Type>Config(options): <Type>Config`. The schema is never\n * re-exported — the public surface is the inferred type + resolver.\n *\n * Index of bags owned here:\n * - **Backoff** — retry pacing (`BackoffOptions`), nested in reaction/action.\n * - **Reaction** — `.do(handler, options)` (`blockOnError` / `maxRetries` / `backoff`).\n * - **Action** — `.on(entry, options)` (`maxRetries` / `backoff`).\n * - **Lane** — `.withLane({...})` (`leaseMillis` / `streamLimit` / `cycleMs`).\n * - **Drain / Settle** — `drain(...)` / `settle(...)` runtime knobs.\n * - **Autoclose** — the `.autocloses` / `ActOptions` autoclose knobs (+ window).\n * - **CircuitBreaker** — the store-op breaker on `ActOptions`.\n * - **Fold** — `projection(...).of(...)` batch-fold knobs.\n *\n * Sibling env/package config (`config()`, `NODE_ENV`, log level) lives in the\n * public `../config.ts` — a different concern (process environment, not\n * builder input). The `@rotorsoft/act-http` transport bags (`SseOptions`,\n * `OpenAPIOptions`) live in that package; core cannot own another package's\n * surface.\n *\n * Validation philosophy: reject only what is genuinely broken — `NaN`,\n * `±Infinity` (Zod 4's `z.number()` rejects both by default), and negatives\n * where nonsensical. A value that works today is never newly rejected. The\n * real strictness lands on `maxRetries` and `backoff`, the knobs whose bad\n * values silently corrupt the poison-quarantine and retry-loop-exit gates.\n *\n * @internal\n */\n\nimport { z } from \"zod\";\nimport type { ActOptions } from \"../act.js\";\nimport type {\n ActionOptions,\n BackoffOptions,\n DrainOptions,\n FoldOptions,\n LaneConfig,\n ReactionOptions,\n SettleOptions,\n} from \"../types/index.js\";\n\n// ---------------------------------------------------------------------------\n// Backoff — retry pacing. Nested inside the reaction/action bags below; also\n// resolvable on its own (`resolveBackoffConfig`) for direct callers.\n// ---------------------------------------------------------------------------\n\n/**\n * Rejects an off-union `strategy`, a non-finite/negative `baseMs`, or a\n * non-finite/non-positive `maxMs` (ACT-1269). Zod 4's `z.number()` rejects\n * `NaN`/`±Infinity` by default, so `.min(0)` / `.gt(0)` also close the\n * non-finite gap. No `maxMs >= baseMs` constraint — a sub-`baseMs` cap on\n * `exponential` is documented behavior, not an error.\n * @internal\n */\nconst BackoffOptionsSchema = z.object({\n strategy: z.enum([\"fixed\", \"linear\", \"exponential\"]),\n baseMs: z.number().min(0),\n maxMs: z.number().gt(0).optional(),\n jitter: z.boolean().optional(),\n});\n\n/** Validate a backoff bag, or pass `undefined` through. Throws `ZodError`. */\nexport function resolveBackoffConfig(\n options: BackoffOptions | undefined\n): BackoffOptions | undefined {\n return options === undefined\n ? undefined\n : BackoffOptionsSchema.parse(options);\n}\n\n// ---------------------------------------------------------------------------\n// Reaction — `.do(handler, options)`. `maxRetries` gates the poison-quarantine\n// decision (`retry >= maxRetries`), so a `NaN` here silently disables\n// `blockOnError` (a poison message retries forever). Validate the whole bag.\n// ---------------------------------------------------------------------------\n\nconst ReactionOptionsSchema = z.object({\n blockOnError: z.boolean(),\n maxRetries: z.number().int().min(0),\n backoff: BackoffOptionsSchema.optional(),\n});\n\n/** Resolved reaction options. */\nexport type ReactionConfig = z.infer<typeof ReactionOptionsSchema>;\n\n/** Validate a fully-defaulted reaction options bag. Throws `ZodError`. */\nexport function resolveReactionConfig(\n options: ReactionOptions\n): ReactionConfig {\n return ReactionOptionsSchema.parse(options);\n}\n\n// ---------------------------------------------------------------------------\n// Action — `.on(entry, options)`. `maxRetries` gates the command retry loop's\n// exit (`attempt >= maxRetries`), so a `NaN` here can spin the loop forever on\n// a contended stream. All fields optional (the argument itself is optional).\n// ---------------------------------------------------------------------------\n\nconst ActionOptionsSchema = z.object({\n maxRetries: z.number().int().min(0).optional(),\n backoff: BackoffOptionsSchema.optional(),\n});\n\n/** Resolved action options. */\nexport type ActionConfig = z.infer<typeof ActionOptionsSchema>;\n\n/** Validate an action options bag. Throws `ZodError`. */\nexport function resolveActionConfig(options: ActionOptions): ActionConfig {\n return ActionOptionsSchema.parse(options);\n}\n\n// ---------------------------------------------------------------------------\n// Lane — `.withLane({...})`. Per-lane overrides of the drain budget. Time\n// knobs (`leaseMillis` / `cycleMs`) accept any non-negative ms; `streamLimit`\n// is an integer count. Reject NaN/Infinity/negative; allow 0 (as today).\n// ---------------------------------------------------------------------------\n\nconst LaneConfigSchema = z.object({\n name: z.string().min(1),\n leaseMillis: z.number().min(0).optional(),\n streamLimit: z.number().int().min(0).optional(),\n cycleMs: z.number().min(0).optional(),\n});\n\n/** Validate a lane config. Throws `ZodError`. Returns the input shape. */\nexport function resolveLaneConfig<TName extends string>(\n options: LaneConfig<TName>\n): LaneConfig<TName> {\n LaneConfigSchema.parse(options);\n return options;\n}\n\n// ---------------------------------------------------------------------------\n// Drain / Settle — runtime knobs for `drain(...)` / `settle(...)`. Parsed once\n// per call (cheap). Reject NaN/Infinity/negative; allow 0. `correlate` is a\n// pass-through query filter (validated by the store), so it is not reshaped.\n// ---------------------------------------------------------------------------\n\nconst DrainOptionsSchema = z.object({\n streamLimit: z.number().int().min(0).optional(),\n eventLimit: z.number().int().min(0).optional(),\n leaseMillis: z.number().min(0).optional(),\n});\n\n/** Validate drain options, or pass `undefined` through. Throws `ZodError`. */\nexport function resolveDrainConfig(\n options: DrainOptions | undefined\n): DrainOptions | undefined {\n if (options === undefined) return undefined;\n DrainOptionsSchema.parse(options);\n return options;\n}\n\nconst SettleOptionsSchema = DrainOptionsSchema.extend({\n debounceMs: z.number().min(0).optional(),\n // `maxPasses` defaults to Infinity (no cap) when omitted; a present value is\n // a non-negative integer — `0` is legal and means \"run no passes\".\n maxPasses: z.number().int().min(0).optional(),\n}).loose();\n\n/** Validate settle options, or pass `undefined` through. Throws `ZodError`. */\nexport function resolveSettleConfig(\n options: SettleOptions | undefined\n): SettleOptions | undefined {\n if (options === undefined) return undefined;\n SettleOptionsSchema.parse(options);\n return options;\n}\n\n// ---------------------------------------------------------------------------\n// Act — the top-level `act().build(options)` scalar knobs. The nested bags\n// (`autocloseWindow`, `circuitBreaker`) are resolved by their own resolvers\n// below; the `scoped`/`correlator` fields are objects/functions passed\n// through untouched (`.loose()`), so only the scalar knobs are checked here.\n// ---------------------------------------------------------------------------\n\nconst ActOptionsSchema = z\n .object({\n maxSubscribedStreams: z.number().int().min(1).optional(),\n settleDebounceMs: z.number().int().min(0).optional(),\n })\n .loose();\n\n/** Validate the scalar `ActOptions` knobs at build. Throws `ZodError`. */\nexport function resolveActConfig(\n options: ActOptions | undefined\n): ActOptions | undefined {\n if (options === undefined) return undefined;\n ActOptionsSchema.parse(options);\n return options;\n}\n\n// ---------------------------------------------------------------------------\n// Autoclose — the autoclose knobs on `ActOptions` (+ the off-hours window).\n// The window *logic* (DST, hour math) stays in `autoclose-window.ts`; only\n// the schema, defaults, and resolver live here.\n// ---------------------------------------------------------------------------\n\n/**\n * @deprecated The cadence knob is derived from `autocloseWindow` now (#1175);\n * nothing consumes it. Kept for compat; removed in the next major.\n */\nexport const DEFAULT_AUTOCLOSE_CYCLE_MINUTES = 720;\n/** @deprecated Dead since #1090 removed the autoclose sweep. */\nexport const DEFAULT_CLOSE_BATCH_SIZE = 64;\n/** @deprecated Dead since #1090 removed the autoclose sweep. */\nexport const DEFAULT_CLOSE_YIELD_MS = 0;\n/** Default IANA zone for `autocloseWindow` when the operator omits one. */\nexport const DEFAULT_AUTOCLOSE_WINDOW_TZ = \"UTC\";\n\n/** True when `tz` is a zone the runtime's `Intl` accepts. @internal */\nfunction is_valid_time_zone(tz: string): boolean {\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: tz });\n return true;\n } catch {\n return false;\n }\n}\n\nconst AutocloseWindowSchema = z\n .object({\n start: z\n .number()\n .int()\n .min(0)\n .max(23, { message: \"autocloseWindow.start must be an hour in [0, 23]\" }),\n end: z\n .number()\n .int()\n .min(0)\n .max(23, { message: \"autocloseWindow.end must be an hour in [0, 23]\" }),\n timeZone: z\n .string()\n .refine(is_valid_time_zone, {\n message: \"autocloseWindow.timeZone must be a valid IANA time zone\",\n })\n .default(DEFAULT_AUTOCLOSE_WINDOW_TZ),\n })\n .refine((w) => w.start !== w.end, {\n message:\n \"autocloseWindow.start and end must differ — an empty window disables autoclose\",\n });\n\nconst AutocloseOptionsSchema = z.object({\n autocloseCycleMinutes: z\n .number()\n .int()\n .min(1)\n .max(1440)\n .default(DEFAULT_AUTOCLOSE_CYCLE_MINUTES),\n closeBatchSize: z\n .number()\n .int()\n .min(1)\n .max(1024)\n .default(DEFAULT_CLOSE_BATCH_SIZE),\n closeYieldMs: z.number().min(0).max(1000).default(DEFAULT_CLOSE_YIELD_MS),\n closeOnError: z.boolean().default(false),\n autocloseWindow: AutocloseWindowSchema.optional(),\n});\n\n/** Resolved autoclose configuration after validation + default expansion. */\nexport type AutocloseConfig = z.infer<typeof AutocloseOptionsSchema>;\n\n/** Validate + default the autoclose knobs on `ActOptions`. Throws `ZodError`. */\nexport function resolveAutocloseConfig(\n options: ActOptions | undefined\n): AutocloseConfig {\n return AutocloseOptionsSchema.parse({\n autocloseCycleMinutes: options?.autocloseCycleMinutes,\n closeBatchSize: options?.closeBatchSize,\n closeYieldMs: options?.closeYieldMs,\n closeOnError: options?.closeOnError,\n autocloseWindow: options?.autocloseWindow,\n });\n}\n\n// ---------------------------------------------------------------------------\n// CircuitBreaker — the store-op breaker on `ActOptions`. The `CircuitBreaker`\n// state machine stays in `circuit-breaker.ts` and imports the resolved type.\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_CIRCUIT_FAILURE_THRESHOLD = 5;\nexport const DEFAULT_CIRCUIT_COOLDOWN_MS = 30_000;\n\nconst CircuitBreakerOptionsSchema = z.object({\n failureThreshold: z\n .number()\n .int()\n .min(1)\n .default(DEFAULT_CIRCUIT_FAILURE_THRESHOLD),\n cooldownMs: z\n .number()\n .int()\n .min(100)\n .max(3_600_000)\n .default(DEFAULT_CIRCUIT_COOLDOWN_MS),\n});\n\n/** Public, all-optional circuit-breaker options bag for `act().build()`. */\nexport type CircuitBreakerOptions = z.input<typeof CircuitBreakerOptionsSchema>;\n\n/** Resolved circuit-breaker configuration. */\nexport type CircuitBreakerConfig = z.infer<typeof CircuitBreakerOptionsSchema>;\n\n/** Parse + apply defaults. Throws `ZodError` on out-of-range values. */\nexport const resolveCircuitBreakerConfig = (\n options?: CircuitBreakerOptions\n): CircuitBreakerConfig => CircuitBreakerOptionsSchema.parse(options ?? {});\n\n// ---------------------------------------------------------------------------\n// Fold — `projection(name).of(state)` batch-fold knobs.\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_FOLD_FLUSH_EVERY = 1_000;\nexport const DEFAULT_MAX_CACHED_STATES = 10_000;\n\nconst FoldOptionsSchema = z.object({\n flushEvery: z.number().int().min(1).default(DEFAULT_FOLD_FLUSH_EVERY),\n maxCachedStates: z.number().int().min(1).default(DEFAULT_MAX_CACHED_STATES),\n});\n\n/** Resolved fold configuration. */\nexport type FoldConfig = z.infer<typeof FoldOptionsSchema>;\n\n/** Validate + default the fold knobs. Throws `ZodError`. */\nexport function resolveFoldConfig(options: FoldOptions): FoldConfig {\n return FoldOptionsSchema.parse(options);\n}\n","/**\n * @module defer-config\n * @category Internal\n *\n * The `when` options for the public `defer` surface (#1091, RFC 0001). A\n * reaction defers itself to a future time either declaratively (the\n * `.defer(when)` builder step) or imperatively (`throw new DeferSignal(when)`\n * inside a handler); both resolve `when` through here.\n *\n * The load-bearing rule is **derivability**. A deferred stream's due-time must\n * be recomputable by whichever worker re-claims it after the wait, so `when`\n * never resolves against `Date.now()`. `after` is measured from the triggering\n * event's `created` timestamp, and `at` is either a fixed `Date` or a pure\n * function of the event. Either way, re-delivering the same event yields the\n * same due-time, which is what makes a defer correct across restarts and\n * competing workers.\n *\n * Validation follows the config-schema standard (CLAUDE.md): an internal\n * `*OptionsSchema` const, a public inferred type, and a resolver. Slice 2\n * ships `after` / `at`; recurrence (`every`) extends this in Slice 3 (#1092).\n *\n * @internal\n */\n\nimport { z } from \"zod\";\nimport type { Committed, DeferWhen, Schemas } from \"../types/index.js\";\nimport { DeferSignal } from \"./defer-signal.js\";\n\n/**\n * A relative span, measured from the triggering event's `created` time. At\n * least one field is required; fields are additive (`{ hours: 1, minutes: 30 }`\n * is 90 minutes).\n */\nconst DeferDurationSchema = z\n .object({\n days: z.number().positive().optional(),\n hours: z.number().positive().optional(),\n minutes: z.number().positive().optional(),\n })\n .strict()\n .refine((d) => d.days != null || d.hours != null || d.minutes != null, {\n message: \"defer: a duration needs at least one of days, hours, or minutes\",\n });\n\n/**\n * Zod schema for the `defer(when)` options bag. Exactly one of `after` / `at`;\n * `at` is an absolute `Date`. Internal per the config standard; the public\n * surface is {@link DeferWhen} and {@link resolve_defer_at}.\n *\n * @internal\n */\nconst DeferWhenSchema = z\n .object({\n after: DeferDurationSchema.optional(),\n at: z.date().optional(),\n })\n .strict()\n .refine((w) => (w.after === undefined) !== (w.at === undefined), {\n message: \"defer: specify exactly one of `after` or `at`\",\n });\n\n/** Sum a duration bag to milliseconds. @internal */\nfunction duration_ms(d: {\n days?: number;\n hours?: number;\n minutes?: number;\n}): number {\n return (\n (d.days ?? 0) * 86_400_000 +\n (d.hours ?? 0) * 3_600_000 +\n (d.minutes ?? 0) * 60_000\n );\n}\n\n/**\n * Resolve `when` to an absolute due-time (ms since epoch) for a given\n * triggering event. Validates via {@link DeferWhenSchema} (throws `ZodError`\n * on a bad shape), then derives the time: `after` from `event.created`, `at`\n * from its absolute `Date`. Never reads `Date.now()`, so the result is stable\n * across re-delivery.\n *\n * @internal\n */\nexport function resolve_defer_at<E extends Schemas>(\n when: DeferWhen,\n event: Committed<E, keyof E>\n): number {\n const parsed = DeferWhenSchema.parse(when);\n if (parsed.after) return event.created.getTime() + duration_ms(parsed.after);\n return parsed.at!.getTime();\n}\n\n/**\n * The schedule handed to the declarative `.defer` builder step: either a\n * literal {@link DeferWhen} (fixed cooldown/deadline) or a function of the\n * triggering event (read the payload to choose the schedule).\n *\n * @internal\n */\nexport type DeferSchedule<TEvent> = DeferWhen | ((event: TEvent) => DeferWhen);\n\n/**\n * Validate a literal `when` at build time (fail fast, per the config-schema\n * standard) — throws `ZodError` on a bad shape (both/neither of `after`/`at`,\n * an empty or non-positive duration). The function form of a `.defer` schedule\n * can only be checked when it runs, so builders pass just the literal here.\n *\n * @internal\n */\nexport function assert_defer_when(when: DeferWhen): void {\n DeferWhenSchema.parse(when);\n}\n\n/**\n * Wrap a reaction handler so it holds until its schedule is due, then runs.\n * On each delivery it resolves the schedule against the triggering event; if\n * the due-time hasn't arrived it throws {@link DeferSignal} (the drain holds\n * the stream, no watermark advance, no retry bump), otherwise it runs the\n * real handler. The wrapper keeps the original handler's `name` so reaction\n * registration and de-dup are unaffected, and preserves the handler's exact\n * type so the builder step is transparent.\n *\n * @internal\n */\nexport function make_deferred<H extends (...args: any[]) => Promise<unknown>>(\n handler: H,\n schedule: DeferSchedule<Parameters<H>[0]>\n): H {\n const call = handler as (...args: unknown[]) => Promise<unknown>;\n const deferred = async (\n event: Parameters<H>[0],\n stream: string,\n app: unknown\n ) => {\n const when = typeof schedule === \"function\" ? schedule(event) : schedule;\n if (Date.now() < resolve_defer_at(when, event)) throw new DeferSignal(when);\n return call(event, stream, app);\n };\n Object.defineProperty(deferred, \"name\", { value: handler.name });\n return deferred as unknown as H;\n}\n","/**\n * @module merge\n * @category Internal\n *\n * Shared utilities for merging partial states and projections across builders.\n * Lives in `internal/` because the symbols are consumed by the builder layer\n * (`act-builder`, `slice-builder`, `projection-builder`) but aren't part of\n * the public package surface.\n *\n * @internal\n */\nimport { ZodObject, type ZodType } from \"zod\";\nimport type { Projection } from \"../builders/projection-builder.js\";\nimport type { Schema, State } from \"../types/index.js\";\n\n/**\n * Unwraps wrapper types (ZodOptional, ZodNullable, ZodDefault, ZodReadonly)\n * to find the base type name, e.g. `z.string().optional()` -> `\"ZodString\"`.\n */\nfunction base_type_name(zodType: ZodType): string {\n let t: any = zodType;\n while (typeof t.unwrap === \"function\") {\n t = t.unwrap();\n }\n return t.constructor.name;\n}\n\n/**\n * Merges two Zod schemas. If both are ZodObject instances, checks for\n * overlapping shape keys with incompatible base types (throws descriptive\n * error), then merges via `.extend()`. Falls back to keeping existing\n * schema if either is not a ZodObject.\n */\nfunction merge_schemas(\n existing: ZodType,\n incoming: ZodType,\n state_name: string\n): ZodType {\n if (existing instanceof ZodObject && incoming instanceof ZodObject) {\n const existing_shape = existing.shape as Record<string, ZodType>;\n const incoming_shape = incoming.shape as Record<string, ZodType>;\n for (const key of Object.keys(incoming_shape)) {\n if (key in existing_shape) {\n const existing_base = base_type_name(existing_shape[key]);\n const incoming_base = base_type_name(incoming_shape[key]);\n if (existing_base !== incoming_base) {\n throw new Error(\n `Schema conflict in \"${state_name}\": key \"${key}\" has type \"${existing_base}\" but incoming partial declares \"${incoming_base}\"`\n );\n }\n }\n }\n return existing.extend(incoming_shape);\n }\n return existing;\n}\n\n/**\n * Merges two init functions by spreading both results together.\n * Each partial only provides its own defaults.\n */\nfunction merge_inits<TState extends Schema>(\n existing: () => Readonly<TState>,\n incoming: () => Readonly<TState>\n): () => Readonly<TState> {\n return () => ({ ...existing(), ...incoming() });\n}\n\n/**\n * Registers a state into a states map and action/event registries,\n * merging with existing same-name states (partial state support).\n */\nexport function register_state(\n state: State<any, any, any>,\n states: Map<string, State<any, any, any>>,\n actions: Record<string, any>,\n events: Record<string, any>\n): void {\n const existing = states.get(state.name);\n if (existing) {\n merge_into_existing(state, existing, states, actions, events);\n } else {\n register_new_state(state, states, actions, events);\n }\n}\n\n/**\n * Registers a state for the first time. All action/event names must be unique\n * across the registry; collisions throw.\n */\nfunction register_new_state(\n state: State<any, any, any>,\n states: Map<string, State<any, any, any>>,\n actions: Record<string, any>,\n events: Record<string, any>\n): void {\n states.set(state.name, state);\n for (const name of Object.keys(state.actions)) {\n if (actions[name]) throw new Error(`Duplicate action \"${name}\"`);\n actions[name] = state;\n }\n for (const name of Object.keys(state.events)) {\n if (events[name]) throw new Error(`Duplicate event \"${name}\"`);\n events[name] = { schema: state.events[name], reactions: new Map() };\n }\n}\n\n/**\n * Merges an incoming partial state into an existing same-name state and\n * updates the action/event registries. Splits into four phases:\n * 1. validate no cross-state action/event collisions\n * 2. merge per-event patches (one custom patch per event)\n * 3. build the merged state and replace it in the states map\n * 4. update action→state pointers and register new events\n */\nfunction merge_into_existing(\n state: State<any, any, any>,\n existing: State<any, any, any>,\n states: Map<string, State<any, any, any>>,\n actions: Record<string, any>,\n events: Record<string, any>\n): void {\n // 1. Validate no cross-state collisions for actions/events\n for (const name of Object.keys(state.actions)) {\n // Same schema reference means the same partial re-registered via another slice\n if (existing.actions[name] === state.actions[name]) continue;\n if (actions[name]) throw new Error(`Duplicate action \"${name}\"`);\n }\n for (const name of Object.keys(state.events)) {\n // Same schema reference means the same partial re-registered via another slice\n if (existing.events[name] === state.events[name]) continue;\n // Same event name registered in a same-name state partial with a\n // different Zod schema reference — silent contract drift that the\n // type system can't catch (structurally compatible shapes flow\n // through TS even when refinements/enums/literals disagree).\n // Reference identity is the rule: cross-slice event schemas must\n // come from a single shared instance.\n if (existing.events[name]) {\n throw new Error(\n `Event \"${name}\" in state \"${state.name}\" is declared with different Zod schemas across slices. ` +\n `Cross-slice event schemas must reference the same instance — ` +\n `extract a shared schema (e.g. \\`export const ${name} = z.object({ ... })\\` in a shared module) ` +\n `and import it in every slice that declares it.`\n );\n }\n if (events[name]) throw new Error(`Duplicate event \"${name}\"`);\n }\n\n // 2. Merge patches with custom-vs-passthrough resolution\n const merged_patch = merge_patches(existing.patch, state.patch, state.name);\n\n // 3. Build merged state\n const merged = {\n ...existing,\n state: merge_schemas(existing.state, state.state, state.name),\n init: merge_inits(existing.init, state.init),\n events: { ...existing.events, ...state.events },\n actions: { ...existing.actions, ...state.actions },\n patch: merged_patch,\n on: { ...existing.on, ...state.on },\n given: { ...existing.given, ...state.given },\n snap:\n state.snap && existing.snap && state.snap !== existing.snap\n ? (() => {\n throw new Error(\n `Duplicate snap strategy for state \"${state.name}\"`\n );\n })()\n : state.snap || existing.snap,\n };\n states.set(state.name, merged);\n\n // 4. Update action→state pointers; register events not yet seen\n for (const name of Object.keys(merged.actions)) {\n actions[name] = merged;\n }\n for (const name of Object.keys(state.events)) {\n if (events[name]) continue; // already registered, preserve reactions\n events[name] = { schema: state.events[name], reactions: new Map() };\n }\n}\n\n/**\n * Merges two patch maps. Only one custom (non-passthrough) patch per event is\n * allowed; passthroughs always yield to custom reducers, and re-registering\n * the same custom patch (same reference, e.g. across slices) is a no-op.\n */\nfunction merge_patches(\n existing: Record<string, any>,\n incoming: Record<string, any>,\n state_name: string\n): Record<string, any> {\n const merged = { ...existing };\n for (const name of Object.keys(incoming)) {\n const existing_p = existing[name];\n const incoming_p = incoming[name];\n if (!existing_p) {\n merged[name] = incoming_p;\n continue;\n }\n const existing_is_default = existing_p._passthrough;\n const incoming_is_default = incoming_p._passthrough;\n if (\n !existing_is_default &&\n !incoming_is_default &&\n existing_p !== incoming_p\n ) {\n throw new Error(\n `Duplicate custom patch for event \"${name}\" in state \"${state_name}\"`\n );\n }\n // Keep whichever is custom; if both passthrough or existing custom, keep existing\n if (existing_is_default && !incoming_is_default) {\n merged[name] = incoming_p;\n }\n }\n return merged;\n}\n\n/**\n * Merges reactions from one event register into another. The target is\n * assumed to already contain entries for every event name in the source\n * (e.g., act-builder's `.withSlice()` registers the slice's states first,\n * which seeds the target events). Reactions are keyed by `handler.name`;\n * two distinct handlers sharing a name on the same event throw rather than\n * silently overwriting (ACT-979). Re-merging the identical reaction object\n * is idempotent — mirrors {@link register_batch_handler}.\n */\nexport function merge_event_register(\n target: Record<string, { reactions: Map<string, unknown> }>,\n source: Record<string, { reactions: Map<string, unknown> }>\n): void {\n for (const [event_name, source_reg] of Object.entries(source)) {\n const target_reg = target[event_name];\n if (!target_reg) continue;\n for (const [name, reaction] of source_reg.reactions) {\n const existing = target_reg.reactions.get(name);\n if (existing !== undefined && existing !== reaction)\n throw new Error(\n `Duplicate reaction \"${name}\" for event \"${event_name}\". ` +\n `Reaction handlers are keyed by function name; rename one of them.`\n );\n target_reg.reactions.set(name, reaction);\n }\n }\n}\n\n/**\n * Merges a projection's event schemas and reactions into an event registry,\n * deduplicating reaction names by appending \"_p\" on collision.\n */\nexport function merge_projection(\n proj: Projection<any>,\n events: Record<string, any>\n): void {\n for (const event_name of Object.keys(proj.events)) {\n const proj_register = proj.events[event_name];\n const existing = events[event_name];\n if (!existing) {\n events[event_name] = {\n schema: proj_register.schema,\n reactions: new Map(proj_register.reactions),\n };\n } else {\n for (const [name, reaction] of proj_register.reactions) {\n // The `_p` rename resolves a NAME collision between two genuinely\n // different handlers. Registering the SAME reaction object again is\n // not a collision — it is the same projection reached along two\n // paths (exported from a module and embedded by two slices, or a\n // `.withProjection(p)` written twice) — and renaming it registered a\n // second copy under `name_p`, so the handler ran twice per event,\n // forever, frozen into the registry at build (#1439).\n //\n // Not the at-least-once redelivery contract: a structural duplicate,\n // deterministic on every event, with no signal anywhere. Both\n // siblings already guard on identity — `merge_event_register` throws\n // on a different handler under the same name, `register_batch_handler`\n // likewise — this one only lacked the check.\n if ([...existing.reactions.values()].includes(reaction)) continue;\n let key = name;\n while (existing.reactions.has(key)) key = `${key}_p`;\n existing.reactions.set(key, reaction);\n }\n }\n }\n}\n\n// Resolves the event stream as source and target (default)\nexport const _this_ = ({ stream }: { stream: string }) => ({\n source: stream,\n target: stream,\n});\n","/**\n * @module builder-utils\n * @category Internal\n *\n * Shared builder machinery reused by both `act-builder.ts` and\n * `slice-builder.ts`. The two builders expose the same reaction-registration\n * and lane-declaration surface and differ only in the concrete builder type\n * they return (`ActBuilder` vs `SliceBuilder`) and the event register they\n * write into (`registry.events` vs the slice's `events`). This module owns the\n * one copy of that logic so the builders stay thin delegations.\n *\n * @internal\n */\n\nimport { DEFAULT_LANE } from \"../ports.js\";\nimport type {\n Committed,\n EventRegister,\n LaneConfig,\n Reaction,\n ReactionHandler,\n ReactionOptions,\n ReactionResolver,\n Schemas,\n} from \"../types/index.js\";\nimport { resolveReactionConfig } from \"./config.js\";\nimport {\n assert_defer_when,\n type DeferSchedule,\n make_deferred,\n} from \"./defer-config.js\";\nimport { _this_ } from \"./merge.js\";\n\n/**\n * Validate and register a drain lane (ACT-1103): the `\"default\"` name is\n * reserved and each lane name must be unique. Mutates `lanes` in place; the\n * caller returns its own builder for chaining.\n *\n * @internal\n */\nexport function register_lane(config: LaneConfig, lanes: LaneConfig[]): void {\n if (config.name === DEFAULT_LANE)\n throw new Error(`Lane \"${DEFAULT_LANE}\" is reserved`);\n if (lanes.some((l) => l.name === config.name))\n throw new Error(`Lane \"${config.name}\" was already declared`);\n lanes.push(config);\n}\n\n/**\n * Build the `.on(event)` step shared by both builders. Registers a reaction\n * (named-function + duplicate guards, fail-fast literal-schedule validation,\n * the default `_this_` resolver, and the `.defer` handler wrap) into\n * `events[event].reactions`, and hands back `builder` patched with `.to(...)`\n * for in-place resolver routing.\n *\n * The strict, builder-specific type is supplied by each builder's own `on`\n * signature ({@link ReactionOn}); the runtime here is builder-agnostic.\n *\n * @internal\n */\nexport function reaction_on<\n TEvents extends Schemas,\n TKey extends keyof TEvents,\n TBuilder,\n>(event: TKey, events: EventRegister<TEvents>, builder: TBuilder) {\n const register = (\n handler: ReactionHandler<TEvents, TKey>,\n options?: Partial<ReactionOptions>,\n schedule?: DeferSchedule<Committed<TEvents, TKey>>\n ) => {\n if (!handler.name)\n throw new Error(\n `Reaction handler for \"${String(event)}\" must be a named function`\n );\n if (events[event].reactions.has(handler.name))\n throw new Error(\n `Duplicate reaction \"${handler.name}\" for event \"${String(event)}\". ` +\n `Reaction handlers are keyed by function name; rename one of them.`\n );\n // Fail fast on a bad literal schedule; the function form is checked when it\n // runs (no event to resolve against at build time).\n if (schedule && typeof schedule !== \"function\") assert_defer_when(schedule);\n const reaction: Reaction<TEvents, TKey> = {\n handler: schedule ? make_deferred(handler, schedule) : handler,\n resolver: _this_,\n // #1269: validate the whole bag at the declaration site so a bad\n // `maxRetries`/`backoff`/`blockOnError` throws ZodError at build,\n // not a NaN gate on the first retry.\n options: resolveReactionConfig({\n blockOnError: options?.blockOnError ?? true,\n maxRetries: options?.maxRetries ?? 3,\n backoff: options?.backoff,\n }),\n };\n // Register once with the default _this_ resolver. If `.to()` is chained\n // next, it patches the same reaction's resolver in place — no second\n // Map.set() round-trip.\n events[event].reactions.set(handler.name, reaction);\n return Object.assign(builder as object, {\n to(resolver: ReactionResolver<TEvents, TKey> | string) {\n reaction.resolver =\n typeof resolver === \"string\" ? { target: resolver } : resolver;\n return builder;\n },\n });\n };\n return {\n do: (\n handler: ReactionHandler<TEvents, TKey>,\n options?: Partial<ReactionOptions>\n ) => register(handler, options),\n defer: (schedule: DeferSchedule<Committed<TEvents, TKey>>) => ({\n do: (\n handler: ReactionHandler<TEvents, TKey>,\n options?: Partial<ReactionOptions>\n ) => register(handler, options, schedule),\n }),\n };\n}\n","/**\n * @module internal/circuit-breaker\n *\n * Orchestrator-level circuit breaker for store operations. The drain loop\n * polls `claim()` continuously; when the backing store goes down every poll\n * throws a {@link StoreError}, and without a breaker the orchestrator would\n * spin at the cycle cadence hammering a dead database and flooding the logs.\n *\n * The breaker collapses that into three states:\n *\n * - **closed** — normal operation; failures are counted.\n * - **open** — `failureThreshold` consecutive failures tripped it; attempts\n * are skipped for `cooldownMs` so the store gets room to recover.\n * - **half-open** — the cooldown elapsed; a single trial attempt is allowed.\n * Success closes the breaker; failure re-opens it and restarts the clock.\n *\n * Time is passed in (`now`) rather than read from the clock so the state\n * machine is deterministic under test.\n */\n\nimport type { CircuitBreakerConfig } from \"./config.js\";\n\n/** Circuit breaker state. */\nexport type CircuitState = \"closed\" | \"open\" | \"half-open\";\n\n// The circuit-breaker config schema, defaults, and resolver live in\n// `./config.js` (the single home for builder-facing config bags). This\n// module keeps only the state machine that consumes the resolved config.\n\n/**\n * Side-effect hooks the orchestrator wires into the breaker so consumers\n * (drain / settle / autoclose) don't each thread their own callbacks.\n */\nexport type CircuitBreakerHooks = {\n /** Invoked on every {@link CircuitBreaker.failed} with the error and state. */\n readonly on_error?: (error: unknown, circuit: CircuitState) => void;\n /**\n * Invoked once, `cooldownMs` after the breaker opens (and again on each\n * re-open). The orchestrator wires it to re-attempt a drain — so recovery\n * is automatic even on the default lane, which has no periodic poller.\n */\n readonly on_retry?: () => void;\n};\n\nexport class CircuitBreaker {\n private _failures = 0;\n private _opened_at: number | undefined;\n private _wake: ReturnType<typeof setTimeout> | undefined;\n private readonly _threshold: number;\n private readonly _cooldown_ms: number;\n private readonly _hooks: CircuitBreakerHooks;\n\n constructor(config: CircuitBreakerConfig, hooks: CircuitBreakerHooks = {}) {\n this._threshold = config.failureThreshold;\n this._cooldown_ms = config.cooldownMs;\n this._hooks = hooks;\n }\n\n /** Current state given the wall-clock `now`. */\n state(now: number): CircuitState {\n if (this._opened_at === undefined) return \"closed\";\n return now - this._opened_at >= this._cooldown_ms ? \"half-open\" : \"open\";\n }\n\n /** A store op passed — reset to closed and cancel any pending retry. */\n passed(): void {\n this._failures = 0;\n this._opened_at = undefined;\n this._clear_wake();\n }\n\n /**\n * A store op failed. Opens the breaker when the consecutive-failure\n * threshold is reached, or immediately re-opens (restarting the cooldown)\n * if a half-open trial just failed. Returns the resulting state.\n *\n * Callers gate on the state directly — `state(now) === \"open\"` means skip.\n * On opening, schedules the `on_retry` wake so recovery is automatic;\n * always surfaces the failure via `on_error`.\n */\n failed(now: number, error?: unknown): CircuitState {\n const circuit = this._advance(now);\n if (circuit === \"open\") this._schedule_wake();\n this._hooks.on_error?.(error, circuit);\n return circuit;\n }\n\n /** Cancel the pending retry timer. Idempotent; call on shutdown. */\n stop(): void {\n this._clear_wake();\n }\n\n /**\n * Schedule the `on_retry` wake `cooldownMs` out so the breaker re-trials\n * the store on its own. No-op when no `on_retry` hook is wired (e.g. unit\n * tests of the pure state machine). The timer is `unref`'d so it never\n * keeps the process alive.\n */\n private _schedule_wake(): void {\n if (!this._hooks.on_retry) return;\n this._clear_wake();\n this._wake = setTimeout(() => {\n this._wake = undefined;\n this._hooks.on_retry?.();\n }, this._cooldown_ms);\n this._wake.unref();\n }\n\n private _clear_wake(): void {\n if (this._wake) {\n clearTimeout(this._wake);\n this._wake = undefined;\n }\n }\n\n /** Pure state transition for a failure — no side effects. */\n private _advance(now: number): CircuitState {\n // Already tripped: this can only be reached from a half-open trial\n // (open skips attempts), so the trial failed — re-open and restart.\n if (this._opened_at !== undefined) {\n this._opened_at = now;\n return \"open\";\n }\n this._failures += 1;\n if (this._failures >= this._threshold) {\n this._opened_at = now;\n return \"open\";\n }\n return \"closed\";\n }\n}\n","/**\n * @module close-cycle\n * @category Internal\n *\n * Pure orchestration of the close-the-books flow: scan stream heads,\n * partition by reaction safety, guard with tombstones, optionally seed\n * restart state, run user archive callbacks, atomically truncate, and\n * update the cache.\n *\n * The Act orchestrator owns lifecycle (correlate gate, emit(\"closed\")) and\n * the registry-derived inputs (reactive-event count, event→state map). All\n * sequential phase work between those state touches lives here.\n *\n * @internal\n */\n\nimport { cache, SNAP_EVENT, store, TOMBSTONE_EVENT } from \"../ports.js\";\nimport type {\n CloseResult,\n CloseTarget,\n Logger,\n Schema,\n State,\n} from \"../types/index.js\";\nimport type { EsOps } from \"./event-sourcing.js\";\n\n/**\n * Dependencies the close cycle needs from the Act orchestrator. Decoupled\n * from `Act` itself so the cycle can be exercised from tests in isolation.\n *\n * @internal\n */\nexport type CloseCycleDeps = {\n readonly reactive_events_size: number;\n readonly event_to_state: ReadonlyMap<string, State<any, any, any>>;\n readonly load: EsOps[\"load\"];\n readonly tombstone: EsOps[\"tombstone\"];\n readonly logger: Logger;\n /**\n * Correlation id for the close transaction. Caller (`Act.close`)\n * computes this via the configured {@link Correlator}, so close\n * commits share the user's chosen id scheme instead of stamping a\n * UUID.\n */\n readonly correlation: string;\n /**\n * Page size for the safety probe's `query_streams` pagination.\n * Defaults to {@link SAFETY_PROBE_PAGE_SIZE}; production callers omit\n * it, tests set a small value to exercise the multi-page path.\n */\n readonly probe_page_size?: number;\n /**\n * Per-stream critical section (#1222). The windowed branch is\n * deliberately guard-free at the store level — a past cutoff makes the\n * boundary immutable, so a concurrent append can never race the prune.\n * But that assumes a *single* closer per stream. A manual\n * `app.close([{stream, before}])` runs `run_close_cycle` directly,\n * bypassing the `__autoclose__:X` lease that would otherwise exclude a\n * concurrent autoclose windowed close, so both closers can archive the\n * same prefix — a double S3 upload / double JSONL append. This runs the\n * given work under a process-local per-stream lock so the two closers\n * serialize; the second sees the already-pruned prefix and skips its\n * archive. Provided by the Act orchestrator (shared across `app.close`\n * and the drain's `on_close`); defaults to identity (no serialization)\n * when the cycle is exercised in isolation.\n */\n readonly with_stream_lock?: <T>(\n stream: string,\n work: () => Promise<T>\n ) => Promise<T>;\n};\n\n/**\n * Page size for the safety probe's keyset pagination over the\n * subscriptions table. Above `query_streams`'s default `limit` of 100\n * to keep the round-trip count low while bounding per-page work.\n *\n * @internal\n */\nexport const SAFETY_PROBE_PAGE_SIZE = 1000;\n\n/**\n * Per-stream scan result: latest non-tombstone domain event metadata.\n * `last_event_name` is always defined — the scan filters tombstones in the\n * callback and queries without `with_snaps`, so any event reaching the\n * callback is a domain event whose name we capture alongside id/version.\n */\ntype StreamHead = {\n readonly max_id: number;\n readonly version: number;\n readonly last_event_name: string;\n /**\n * Set when the stream already carries a tombstone but still holds domain\n * events — a close that wrote its guard and was then interrupted before\n * truncating (a throwing archive callback, or a `truncate` that failed).\n * Carries the existing guard's event id so the retry resumes at Phase 4\n * instead of re-tombstoning (which would fail the version guard) or being\n * dropped from the scan entirely (#1389).\n */\n readonly resumed_guard?: { readonly id: number };\n};\n\n/**\n * Run the full close cycle for the given targets. Caller owns the\n * lifecycle event emission.\n *\n * Targets carrying a `before` cutoff take the **windowed** branch — a\n * pure prefix delete behind an existing snapshot (see\n * {@link run_windowed_closes}); the rest run the guarded\n * tombstone/restart pipeline below.\n *\n * @internal\n */\nexport async function run_close_cycle(\n targets: CloseTarget[],\n deps: CloseCycleDeps\n): Promise<CloseResult> {\n // Caller (Act.close) filters empty targets; run_close_cycle assumes at\n // least one target.\n const target_map = new Map(targets.map((t) => [t.stream, t]));\n for (const t of target_map.values()) {\n if (t.before !== undefined && t.restart)\n throw new Error(\n `close: \\`before\\` and \\`restart\\` are mutually exclusive (stream \"${t.stream}\") — a windowed close keeps the stream live behind a real snapshot; restart reseeds it`\n );\n }\n const windowed = [...target_map.values()].filter(\n (t) => t.before !== undefined\n );\n const full = [...target_map.values()].filter((t) => t.before === undefined);\n const skipped: string[] = [];\n const windowed_result = windowed.length\n ? await run_windowed_closes(windowed, deps, skipped)\n : new Map();\n if (!full.length) return { truncated: windowed_result, skipped };\n const streams = full.map((t) => t.stream);\n\n // 1. Scan: find the latest non-tombstone event per stream\n const stream_info = await scan_stream_heads(streams);\n\n // 1b. Reject restart targets whose owning state carries sensitive\n // fields, BEFORE anything is written. The seed load in phase 4 is\n // actorless, so every `sensitive()` field would fold to the redaction\n // sentinel and the truncate would then delete the originals — and\n // loading privileged instead would persist plaintext into\n // `__snapshot__.data`, which `forget_pii` cannot reach (the reason\n // `.snap()` is rejected at build time for these states). Such a stream\n // cannot be restarted at all, so it must not be closed either: the\n // caller asked to keep the aggregate alive, and tombstoning it instead\n // would be a strictly more destructive outcome than the one requested.\n // It lands in `skipped`, the established channel for \"couldn't do this\n // one\", with nothing mutated.\n for (const target of full) {\n if (!target.restart) continue;\n const info = stream_info.get(target.stream);\n if (!info) continue;\n const owner = deps.event_to_state.get(info.last_event_name);\n if (owner?.pii_aware) {\n deps.logger.error(\n `Refusing to close \"${target.stream}\" with restart: state \"${owner.name}\" carries sensitive fields, so a restart seed would persist redacted values while deleting the originals. Close it without restart to retire the stream, or leave it open.`\n );\n skipped.push(target.stream);\n stream_info.delete(target.stream);\n }\n }\n\n // 2. Partition: skip streams with pending reactions in flight\n const safe = await partition_by_safety(\n stream_info,\n deps.reactive_events_size,\n skipped,\n deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE\n );\n if (!safe.length) return { truncated: windowed_result, skipped };\n\n // 3. Guard: commit a tombstone with expectedVersion per safe stream.\n // Correlation comes from the orchestrator's configured correlator so\n // close commits share the app's id scheme — see ACT-404.\n const { guarded, guard_events } = await guard_with_tombstones(\n safe,\n stream_info,\n deps.correlation,\n deps.tombstone,\n skipped\n );\n if (!guarded.length) return { truncated: windowed_result, skipped };\n\n // 4. Seed: load final state for restart targets through the owning state\n const seed_states = await load_restart_seeds(\n guarded,\n target_map,\n stream_info,\n deps.event_to_state,\n deps.load,\n deps.logger\n );\n\n // 5. Archive: user-provided per-stream callback while guarded\n await run_archive_callbacks(guarded, target_map);\n\n // 6. Truncate + seed: atomic per-store transaction\n const truncated = await truncate_and_warm_cache(\n guarded,\n seed_states,\n guard_events,\n deps.correlation\n );\n\n for (const [stream, entry] of windowed_result) truncated.set(stream, entry);\n return { truncated, skipped };\n}\n\n// ---------------------------------------------------------------------------\n// Windowed branch — prune the prefix behind an existing snapshot\n// ---------------------------------------------------------------------------\n\n/**\n * Run the windowed closes: probe the min consumer watermark per stream\n * (the `max_id` cap that keeps the boundary at/below what the laggiest\n * consumer has read), run archive callbacks against the cutoff, then\n * hand the boundary targets to {@link Store.truncate}.\n *\n * No tombstone guard and no cache touch — the cutoff is always in the\n * past, so a concurrently-written snapshot (`created = now`) can never\n * become the boundary: once the cutoff is fixed the boundary snapshot is\n * fixed, and the prefix below it is immutable. Concurrent appends land\n * at the head, above the boundary. Current state is unchanged, so the\n * cache stays warm. Streams the store skips (no qualifying snapshot)\n * are reported in `skipped`.\n *\n * @internal\n */\nasync function run_windowed_closes(\n windowed: CloseTarget[],\n deps: CloseCycleDeps,\n skipped: string[]\n): Promise<CloseResult[\"truncated\"]> {\n // 1. Safety probe: min consumer watermark per stream. Skipped entirely\n // when the app has no reactions — nothing can lag.\n const min_at =\n deps.reactive_events_size > 0\n ? await probe_min_watermarks(\n windowed.map((t) => t.stream),\n deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE\n )\n : new Map<string, number>();\n\n // 2 + 3. Per stream, under a process-local lock (#1222): probe the\n // boundary, archive against intact history only when the prune would\n // actually delete a prefix, then truncate. Serialization + the\n // \"prune is non-empty\" gate together make the archive fire at most\n // once per pruned range when a manual `app.close` races an autoclose\n // windowed close for the same stream — the second closer, run behind\n // the lock, sees the already-pruned prefix (boundary is now the\n // earliest event) and skips its archive. Each stream is independent,\n // so `truncate` is called per stream inside its own lock rather than\n // once for the batch; a windowed truncate touches only its own stream.\n const with_lock = deps.with_stream_lock ?? ((_stream, work) => work());\n const truncated: CloseResult[\"truncated\"] = new Map();\n for (const t of windowed) {\n const entry = await with_lock(t.stream, async () => {\n const max_id = min_at.get(t.stream);\n // Boundary probe: will a windowed truncate prune anything? The\n // store deletes events with `id < boundary.id`, where `boundary`\n // is the latest `__snapshot__` with `created < before` (and, when\n // capped, `id <= max_id`). No such prefix ⇒ archive is skipped and\n // the stream is reported skipped, exactly as a no-op truncate would.\n if (!(await windowed_prune_pending(t.stream, t.before!, max_id)))\n return undefined;\n // Archive: user callback against the cutoff, run while the prefix\n // is still present. Sequential/fail-fast: a throw propagates to the\n // caller and leaves the stream un-truncated (no data loss).\n if (t.archive) await t.archive();\n // Boundary truncate: atomic per-store transaction; no seed.\n const result = await store().truncate([\n { stream: t.stream, before: t.before!, max_id },\n ]);\n return result.get(t.stream);\n });\n if (entry) truncated.set(t.stream, entry);\n else skipped.push(t.stream);\n }\n return truncated;\n}\n\n/**\n * Read-only probe: would a windowed truncate of `stream` at `before`\n * (optionally capped at `max_id`) delete a prefix? Mirrors the store's\n * boundary rule — the latest `__snapshot__` with `created < before` and,\n * when capped, `id <= max_id` — then reports whether any event sorts\n * strictly below that boundary. False when no snapshot qualifies (a\n * no-op truncate) or when the boundary is already the earliest event\n * (the prefix was pruned by a prior closer). This is the guard that\n * makes the windowed archive fire at most once per pruned range (#1222).\n *\n * @internal\n */\nasync function windowed_prune_pending(\n stream: string,\n before: Date,\n max_id: number | undefined\n): Promise<boolean> {\n let boundary_id: number | undefined;\n let min_id: number | undefined;\n await store().query(\n (event) => {\n if (min_id === undefined || event.id < min_id) min_id = event.id;\n if (\n event.name === SNAP_EVENT &&\n event.created < before &&\n (max_id === undefined || event.id <= max_id) &&\n (boundary_id === undefined || event.id > boundary_id)\n )\n boundary_id = event.id;\n },\n { stream, stream_exact: true, with_snaps: true, after: -1 }\n );\n // No qualifying snapshot → nothing to prune behind. Otherwise a prune\n // is pending only when some event sorts below the boundary.\n return boundary_id !== undefined && min_id! < boundary_id;\n}\n\n/**\n * Min subscription watermark per target stream — the read-only probe\n * backing the windowed close's `max_id` cap. Pagination and source\n * matching mirror {@link partition_by_safety}; instead of flagging\n * pending streams it folds `min(at)` per stream. Streams with no\n * matching subscriptions are absent (no cap).\n *\n * @internal\n */\nasync function probe_min_watermarks(\n streams: string[],\n page_size: number\n): Promise<Map<string, number>> {\n const min_at = new Map<string, number>();\n const source_regex = new Map<string, RegExp>();\n const get_regex = (source: string): RegExp => {\n let re = source_regex.get(source);\n if (!re) {\n re = new RegExp(source);\n source_regex.set(source, re);\n }\n return re;\n };\n\n let after: string | undefined;\n for (;;) {\n let last: string | undefined;\n const { count } = await store().query_streams(\n (position) => {\n last = position.stream;\n const source_re = position.source\n ? get_regex(position.source)\n : undefined;\n for (const stream of streams) {\n if (!source_re || source_re.test(stream)) {\n const prev = min_at.get(stream);\n if (prev === undefined || position.at < prev)\n min_at.set(stream, position.at);\n }\n }\n },\n { after, limit: page_size, source_matches: streams }\n );\n if (count < page_size) break;\n after = last;\n }\n return min_at;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 1 — scan stream heads\n// ---------------------------------------------------------------------------\n\nasync function scan_stream_heads(\n streams: string[]\n): Promise<Map<string, StreamHead>> {\n // query_stats returns the latest non-snap event per stream (heads-only\n // cheap path, indexed). Streams whose latest non-snap event is a tombstone\n // are filtered out in the loop — we don't want to re-tombstone an\n // already-closed stream. Streams with no events (or only snap/tombstone\n // events filtered out) are absent from the result map entirely.\n const stats = await store().query_stats(streams, {\n exclude: [SNAP_EVENT],\n });\n // Domain head, markers excluded. A stream absent here has no domain\n // events left, so a previous close ran to completion and there is\n // nothing to do. A stream present here whose `stats` head is a tombstone\n // was guarded and then interrupted — it must be resumed, not skipped\n // (#1389). `last_event_name` also has to come from this pass: the\n // restart-seed owner lookup needs the domain event, not the marker.\n const domain_heads = await store().query_stats(streams, {\n exclude: [SNAP_EVENT, TOMBSTONE_EVENT],\n });\n // The tombstone's optimistic lock must expect the stream's ACTUAL current\n // version, which is one higher when a `__snapshot__` trails the domain head\n // — `snap()` commits it into the next version slot (event-sourcing.ts). The\n // domain head above still drives `max_id` (the safety probe: a subscription\n // advances its watermark on domain events, never snapshots) and\n // `last_event_name` (the restart-seed owner lookup). Only the guard version\n // needs the true head, so a second heads-only pass reads it with snapshots\n // included. Without this, a terminal commit that crossed a `.snap()`\n // boundary makes the guard expect a stale version and skip the close (#1356).\n const true_heads = await store().query_stats(streams, {});\n const out = new Map<string, StreamHead>();\n for (const [stream, { head }] of domain_heads) {\n const marker_head = stats.get(stream)?.head;\n const interrupted = marker_head?.name === TOMBSTONE_EVENT;\n out.set(stream, {\n max_id: head.id,\n version: true_heads.get(stream)!.head.version,\n last_event_name: head.name as string,\n ...(interrupted ? { resumed_guard: { id: marker_head.id } } : {}),\n });\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2 — partition by safety\n// ---------------------------------------------------------------------------\n\nasync function partition_by_safety(\n stream_info: Map<string, StreamHead>,\n reactive_events_size: number,\n skipped: string[],\n page_size: number\n): Promise<string[]> {\n if (reactive_events_size === 0) return [...stream_info.keys()];\n\n // Read-only probe: query_streams returns subscription positions without\n // leasing or mutating retry state.\n //\n // The stored `source` on a subscription may be a literal stream name or\n // a pattern (e.g. `^(A|B)$`); this probe matches it as a regex against\n // close-target names either way — a literal regex-matches itself, and a\n // pattern matches the streams it claims for. Any metacharacter\n // over-match only widens the pending set — the conservative direction\n // for a safety probe. Compiled patterns are cached because dynamic\n // reactions commonly produce many subscriptions sharing one source, so\n // the callback fires repeatedly with the same `source`.\n const pending_set = new Set<string>();\n const source_regex = new Map<string, RegExp>();\n const get_regex = (source: string): RegExp => {\n let re = source_regex.get(source);\n if (!re) {\n re = new RegExp(source);\n source_regex.set(source, re);\n }\n return re;\n };\n\n // `source_matches` narrows the probe server-side to subscriptions that\n // could consume from a stream we're closing — a best-effort hint, so\n // the per-position source/target re-check below still runs and keeps\n // the result correct even when a store returns a superset.\n const targets = [...stream_info.keys()];\n\n // Keyset-paginate the (narrowed) subscriptions on the `after` cursor —\n // `query_streams` caps each call at `limit` rows, so every page is\n // inspected until a short page signals the last one. A lagging reaction\n // marks its close target pending regardless of how far its subscription\n // sorts past the first page.\n let after: string | undefined;\n for (;;) {\n let last: string | undefined;\n const { count } = await store().query_streams(\n (position) => {\n last = position.stream;\n const source_re = position.source\n ? get_regex(position.source)\n : undefined;\n for (const [stream, info] of stream_info) {\n if (\n (!source_re || source_re.test(stream)) &&\n position.at < info.max_id\n ) {\n pending_set.add(stream);\n }\n }\n },\n { after, limit: page_size, source_matches: targets }\n );\n if (count < page_size) break;\n after = last;\n }\n\n const safe: string[] = [];\n for (const [stream] of stream_info) {\n if (pending_set.has(stream)) skipped.push(stream);\n else safe.push(stream);\n }\n return safe;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 3 — guard with tombstones\n// ---------------------------------------------------------------------------\n\nasync function guard_with_tombstones(\n safe: string[],\n stream_info: Map<string, StreamHead>,\n correlation: string,\n tombstone: EsOps[\"tombstone\"],\n skipped: string[]\n): Promise<{\n guarded: string[];\n guard_events: Map<string, { id: number; stream: string }>;\n}> {\n const guarded: string[] = [];\n const guard_events = new Map<string, { id: number; stream: string }>();\n await Promise.all(\n safe.map(async (stream) => {\n const info = stream_info.get(stream)!;\n if (info.resumed_guard) {\n // Guard already written by the interrupted run — reuse it rather\n // than re-tombstoning (the version guard would reject it anyway).\n guarded.push(stream);\n guard_events.set(stream, { id: info.resumed_guard.id, stream });\n return;\n }\n const committed = await tombstone(stream, info.version, correlation);\n if (committed) {\n guarded.push(stream);\n guard_events.set(stream, { id: committed.id, stream });\n } else {\n // ConcurrencyError → another writer beat the guard\n skipped.push(stream);\n }\n })\n );\n return { guarded, guard_events };\n}\n\n// ---------------------------------------------------------------------------\n// Phase 4 — load restart seeds\n// ---------------------------------------------------------------------------\n\nasync function load_restart_seeds(\n guarded: string[],\n target_map: Map<string, CloseTarget>,\n stream_info: Map<string, StreamHead>,\n event_to_state: ReadonlyMap<string, State<any, any, any>>,\n load: EsOps[\"load\"],\n logger: Logger\n): Promise<Map<string, Schema>> {\n const seed_states = new Map<string, Schema>();\n await Promise.all(\n guarded\n .filter((s) => target_map.get(s)?.restart)\n .map(async (stream) => {\n // stream_info entry is guaranteed (guarded ⊆ stream_info.keys()).\n const last_event_name = stream_info.get(stream)!.last_event_name;\n const owner_state = event_to_state.get(last_event_name);\n if (!owner_state) {\n // No registered state owns the stream's events (deleted state,\n // schema versioning gone wrong, etc.). Tombstone instead of\n // seeding a corrupted snapshot.\n logger.error(\n `Cannot seed restart for \"${stream}\": no registered state owns event \"${last_event_name}\". Stream will be tombstoned instead.`\n );\n return;\n }\n const snap = await load(owner_state, { stream });\n seed_states.set(stream, snap.state as Schema);\n })\n );\n return seed_states;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 5 — archive callbacks\n// ---------------------------------------------------------------------------\n\nasync function run_archive_callbacks(\n guarded: string[],\n target_map: Map<string, CloseTarget>\n): Promise<void> {\n // Sequential — user callbacks may share resources (S3 client, etc.) and\n // a failure should propagate to the caller without leaving partial state.\n for (const stream of guarded) {\n const archive_fn = target_map.get(stream)?.archive;\n if (archive_fn) await archive_fn();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Phase 6 — atomic truncate + cache warm\n// ---------------------------------------------------------------------------\n\nasync function truncate_and_warm_cache(\n guarded: string[],\n seed_states: Map<string, Schema>,\n guard_events: Map<string, { id: number; stream: string }>,\n correlation: string\n): Promise<CloseResult[\"truncated\"]> {\n const trunc_targets = guarded.map((stream) => {\n const snapshot = seed_states.get(stream);\n const guard = guard_events.get(stream)!;\n return {\n stream,\n snapshot,\n meta: {\n correlation,\n causation: {\n event: { id: guard.id, name: TOMBSTONE_EVENT, stream: guard.stream },\n },\n },\n };\n });\n const truncated = await store().truncate(trunc_targets);\n\n // Cache invalidate / warm — use real event IDs from committed events\n await Promise.all(\n guarded.map(async (stream) => {\n const entry = truncated.get(stream);\n const state = seed_states.get(stream);\n if (state && entry) {\n await cache().set(stream, {\n stream,\n state,\n version: entry.committed.version,\n event_id: entry.committed.id,\n patches: 0,\n snaps: 1,\n });\n } else {\n await cache().invalidate(stream);\n }\n })\n );\n\n return truncated;\n}\n","/**\n * @module correlate-cycle\n * @category Internal\n *\n * Correlation — the discovery half of the correlate→drain pair. Owns the\n * lazy init (subscribe static targets, read cold-start watermark), the\n * dynamic-resolver scan that registers new streams as events arrive, and\n * the periodic timer that drives background discovery.\n *\n * The Act orchestrator passes registry + classification (which static\n * targets to subscribe, whether any dynamic resolvers exist) at build\n * time; everything past that lives here.\n *\n * @internal\n */\n\nimport { log, store } from \"../ports.js\";\nimport type {\n Query,\n ReactionPayload,\n Registry,\n SchemaRegister,\n Schemas,\n} from \"../types/index.js\";\nimport type { DrainOps } from \"./drain.js\";\nimport { LruMap } from \"./lru-map.js\";\n\n/**\n * Cold-start back-scan window (ACT-1207). On init the correlate cursor\n * would otherwise jump straight to the store watermark (`max(at)` across\n * every subscribed stream). A dynamic-resolver event committed but not\n * yet correlated before a crash sits *below* that watermark whenever a\n * busier stream has since advanced — so a plain `max(at)` cold start\n * skips it forever, and a one-shot dynamic target is never subscribed.\n *\n * Flooring the cold-start checkpoint at `watermark - BACK_SCAN` re-scans\n * the tail on restart so those in-flight events are re-discovered.\n * Re-scanning already-correlated events is harmless: `_subscribed`\n * dedups and `subscribe` is an idempotent UPSERT. The window bounds the\n * one-time restart cost; steady-state correlation still advances the\n * checkpoint forward normally.\n *\n * @internal\n */\nconst DEFAULT_COLD_START_BACK_SCAN = 10_000;\n\n/**\n * Static resolver target collected at build time. Subscribed once during\n * init; never re-evaluated.\n *\n * @property priority - Scheduling priority for the resolved target stream.\n * Combined with peers via `max()` at build time when multiple reactions\n * target the same stream — see `build-classify.ts`.\n *\n * @internal\n */\nexport type StaticTarget = {\n readonly stream: string;\n readonly source?: string;\n readonly priority?: number;\n readonly lane?: string;\n};\n\n/**\n * Drives correlation for one Act instance. Owns the checkpoint, the\n * subscribed-streams LRU, and the periodic timer.\n *\n * @internal\n */\n/**\n * Constructor dependencies for {@link CorrelateCycle}. A named bag rather\n * than a positional list: the trailing hooks (`on_init`, `on_init_async`)\n * plus `cold_start_back_scan` are all optional and easy to transpose\n * positionally, so callers pass them by name.\n */\nexport type CorrelateCycleDeps<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n> = {\n registry: Registry<TSchemaReg, TEvents, TActions>;\n static_targets: ReadonlyArray<StaticTarget>;\n has_dynamic_resolvers: boolean;\n cd: DrainOps<TEvents>;\n max_subscribed_streams: number;\n run_scoped: <T>(fn: () => Promise<T>) => Promise<T>;\n on_init?: () => void;\n on_init_async?: () => Promise<void>;\n cold_start_back_scan?: number;\n};\n\nexport class CorrelateCycle<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n> {\n private _checkpoint = -1;\n private _initialized = false;\n /** In-flight init, memoized for single-flight and cleared on failure. */\n private _init_promise: Promise<void> | undefined;\n private _timer: ReturnType<typeof setInterval> | undefined = undefined;\n // target → the priority it was last subscribed at. A dynamic target is\n // re-subscribed (so the store's `GREATEST` upsert runs) only when a later\n // scan resolves a *higher* priority for it — the runtime `max()` invariant\n // (#1363). Static targets are recorded at +Infinity so a dynamic resolution\n // never re-opens them (their priority is owned by the build-time subscribe).\n private readonly _subscribed: LruMap<string, number>;\n private readonly _registry: Registry<TSchemaReg, TEvents, TActions>;\n private readonly _static_targets: ReadonlyArray<StaticTarget>;\n private readonly _has_dynamic_resolvers: boolean;\n private readonly _cd: DrainOps<TEvents>;\n private readonly _on_init: (() => void) | undefined;\n /**\n * Async cold-start hook (#1221). Runs once, after the sync `on_init`,\n * inside the same `init()` await. The orchestrator uses it to re-seed the\n * process-local defer timers from the store's persisted `deferred_at` so\n * an idle deferred stream re-arms its drain across a restart. Kept\n * separate from `on_init` because seeding is an async store read; `init`\n * already awaits, so folding it in here preserves the \"runs exactly once\"\n * guarantee without a second gate on the Act side.\n */\n private readonly _on_init_async: (() => Promise<void>) | undefined;\n /**\n * Scope runner (#1191). The periodic `start_polling` timer fires\n * outside any caller frame, so its `correlate()` must be re-wrapped in\n * the Act's `_scoped` bag or `store()`/`cache()` resolve to the\n * singleton for a scoped Act. The orchestrator always threads its\n * `_scoped` (identity for a non-scoped Act), so it's required.\n */\n private readonly _run_scoped: <T>(fn: () => Promise<T>) => Promise<T>;\n /**\n * Tail re-scan window applied to the cold-start checkpoint (ACT-1207).\n * See {@link DEFAULT_COLD_START_BACK_SCAN}. Constructor arg (not a\n * public option) so tests can shrink it; defaults otherwise.\n */\n private readonly _cold_start_back_scan: number;\n\n constructor({\n registry,\n static_targets,\n has_dynamic_resolvers,\n cd,\n max_subscribed_streams,\n run_scoped,\n on_init,\n on_init_async,\n cold_start_back_scan = DEFAULT_COLD_START_BACK_SCAN,\n }: CorrelateCycleDeps<TSchemaReg, TEvents, TActions>) {\n this._subscribed = new LruMap(max_subscribed_streams);\n this._registry = registry;\n this._static_targets = static_targets;\n this._has_dynamic_resolvers = has_dynamic_resolvers;\n this._cd = cd;\n this._on_init = on_init;\n this._run_scoped = run_scoped;\n this._on_init_async = on_init_async;\n this._cold_start_back_scan = cold_start_back_scan;\n }\n\n /** Last correlated event id. */\n get checkpoint(): number {\n return this._checkpoint;\n }\n\n /**\n * Whether any reaction uses a dynamic resolver — i.e. whether `correlate`\n * performs a store scan rather than the static no-op early-return. The\n * settle loop reads this to avoid recording a fictitious circuit-breaker\n * success on a static app whose correlate never touches the store (#1329).\n */\n get has_dynamic_resolvers(): boolean {\n return this._has_dynamic_resolvers;\n }\n\n /**\n * Initialize correlation state on first call.\n * - Reads max(at) from store, then floors the cold-start checkpoint at\n * `watermark - back_scan` when dynamic resolvers exist, so an event\n * committed-but-not-correlated before a crash is re-scanned on\n * restart instead of skipped (ACT-1207)\n * - Subscribes static resolver targets (idempotent upsert)\n * - Populates the subscribed-streams LRU\n * - Fires `on_init` once (Act uses this to flag a cold-start drain)\n */\n async init(): Promise<void> {\n if (this._initialized) return;\n // Single-flight, but retryable: the promise is memoized so concurrent\n // callers (correlate, the settle loop, every lane worker) share one\n // run, and cleared on rejection so a transient store failure doesn't\n // latch. Setting a boolean before the await instead left every static\n // target unsubscribed for the process lifetime after one blip — the\n // reaction pipeline silently dead, with nothing in blocked_streams or\n // the audit to reveal it, because the subscription row never existed.\n if (!this._init_promise) {\n this._init_promise = this._run_init().catch((error) => {\n this._init_promise = undefined;\n throw error;\n });\n }\n await this._init_promise;\n this._initialized = true;\n }\n\n private async _run_init(): Promise<void> {\n const { watermark } = await store().subscribe([...this._static_targets]);\n // Without dynamic resolvers correlate never scans, so the checkpoint\n // is inert — keep the plain `max(at)` cold start. With dynamic\n // resolvers, back the cursor off the watermark by a bounded window so\n // the crash-window tail (an uncorrelated event now below a busier\n // stream's watermark) is re-discovered. Never floor below -1.\n this._checkpoint = this._has_dynamic_resolvers\n ? Math.max(-1, watermark - this._cold_start_back_scan)\n : watermark;\n this._on_init?.();\n for (const { stream } of this._static_targets) {\n // +Infinity: a dynamic resolution's priority can never exceed it, so a\n // static target is never re-subscribed through the dynamic path (#1363).\n this._subscribed.set(stream, Number.POSITIVE_INFINITY);\n }\n // Cold-start defer re-seed (#1221) — after the static targets are\n // subscribed, so a walk of the streams table sees them.\n await this._on_init_async?.();\n }\n\n /**\n * Forget targets whose subscription rows no longer exist, so a later\n * scan can re-subscribe them.\n *\n * A full close deletes the closed stream's subscription row. The\n * in-process dedup would otherwise still believe the target is\n * subscribed and never re-issue `subscribe()`, silently stopping\n * delivery for any reaction whose target is named after the stream —\n * the documented per-aggregate shape `.to(e => ({target: e.stream}))`\n * makes those two namespaces collide by construction (#1398).\n *\n * Static targets are left alone: they are subscribed once at init and\n * recorded at +Infinity so the dynamic path never re-opens them.\n */\n forget_subscribed(streams: Iterable<string>): void {\n const statics = new Set(this._static_targets.map((t) => t.stream));\n for (const stream of streams) {\n if (!statics.has(stream)) this._subscribed.delete(stream);\n }\n }\n\n /**\n * Discover dynamic-resolver targets in the events past the checkpoint\n * and register any new streams via `cd.subscribe`. Static targets are\n * subscribed at init time, so this only walks dynamic resolvers.\n */\n async correlate(\n query: Query = { after: -1, limit: 10 }\n ): Promise<{ subscribed: number; last_id: number }> {\n await this.init();\n\n // No dynamic resolvers — nothing to discover\n if (!this._has_dynamic_resolvers)\n return { subscribed: 0, last_id: this._checkpoint };\n\n // Use checkpoint as floor, allow explicit query.after to override upward\n const after = Math.max(this._checkpoint, query.after || -1);\n const correlated = new Map<\n string,\n {\n source?: string;\n priority: number;\n lane?: string;\n payloads: ReactionPayload<TEvents>[];\n }\n >();\n let last_id = after;\n await store().query<TEvents>(\n (event) => {\n last_id = event.id;\n const register = this._registry.events[event.name];\n // skip events with no registered reactions\n if (register) {\n for (const reaction of register.reactions.values()) {\n // only evaluate dynamic resolvers — statics are subscribed at init\n if (typeof reaction.resolver !== \"function\") continue;\n const resolved = reaction.resolver(event);\n // Let a target through when a scan resolves a strictly higher\n // priority than it was last subscribed at, so the store's\n // `GREATEST` upsert raises it — the documented runtime `max()`\n // invariant, which the plain \"already subscribed?\" dedup silently\n // froze at first discovery (#1363). A never-seen target defaults to\n // -Infinity so its first resolution always passes; static targets\n // sit at +Infinity so a dynamic resolution never re-opens them.\n if (\n resolved &&\n (resolved.priority ?? 0) >\n (this._subscribed.get(resolved.target) ??\n Number.NEGATIVE_INFINITY)\n ) {\n const incoming_priority = resolved.priority ?? 0;\n const entry = correlated.get(resolved.target) || {\n source: resolved.source,\n priority: incoming_priority,\n lane: resolved.lane,\n payloads: [],\n };\n // Multiple reactions targeting the same stream within a\n // single correlate scan — keep the max priority, and carry the\n // winning reaction's lane so the highest-priority reaction sets\n // the lane (matches the subscribe-side `max()` invariant).\n if (incoming_priority > entry.priority) {\n entry.priority = incoming_priority;\n entry.lane = resolved.lane;\n }\n entry.payloads.push({\n ...reaction,\n source: resolved.source,\n event,\n });\n correlated.set(resolved.target, entry);\n }\n }\n }\n },\n { ...query, after }\n );\n\n if (correlated.size) {\n const streams = [...correlated.entries()].map(\n ([stream, { source, priority, lane }]) => ({\n stream,\n source,\n priority,\n lane,\n })\n );\n const { subscribed } = await this._cd.subscribe(streams);\n // Advance checkpoint only after subscribe succeeds\n this._checkpoint = last_id;\n if (subscribed) {\n // Record each target at the priority it was just subscribed at (the\n // within-scan max), so a later lower-or-equal resolution dedups and a\n // strictly-higher one re-opens the guard above (#1363).\n for (const { stream, priority } of streams) {\n this._subscribed.set(stream, priority);\n }\n }\n return { subscribed, last_id };\n }\n // No streams to subscribe — safe to advance\n this._checkpoint = last_id;\n return { subscribed: 0, last_id };\n }\n\n /**\n * Start a periodic correlation worker. Returns false if one is already\n * running. Errors from `correlate()` are routed through `log()` so they\n * land in the configured logger (the timer keeps running on failure).\n */\n start_polling(\n query: Query = {},\n frequency = 10_000,\n callback?: (subscribed: number) => void\n ): boolean {\n if (this._timer) return false;\n\n const limit = query.limit || 100;\n this._timer = setInterval(\n () =>\n this._run_scoped(() =>\n this.correlate({ ...query, after: this._checkpoint, limit })\n )\n .then((result) => {\n if (callback && result.subscribed) callback(result.subscribed);\n })\n .catch((err) => log().error(err)),\n frequency\n );\n return true;\n }\n\n /** Stop the periodic correlation worker. Idempotent. */\n stop_polling(): void {\n if (this._timer) {\n clearInterval(this._timer);\n this._timer = undefined;\n }\n }\n}\n","/**\n * @module correlator\n * @category Internal\n *\n * Correlation-id generator and the default implementation (ACT-404).\n *\n * The default produces a readable, time-monotonic-within-window, lowercase\n * id like `coun-incr-lwxk9p3a` — short enough to scan in logs, structured\n * enough to identify the originating state/action, and well-distributed\n * enough that competing-consumer workers don't collide.\n *\n * Apps override via {@link ActOptions.correlator} to plug in any scheme\n * (tenant-prefixed, trace-id-propagated, DB-sequence-backed, etc.).\n *\n * @internal\n */\n\nimport { randomInt } from \"node:crypto\";\nimport type { Actor, Correlator } from \"../types/index.js\";\n\nconst BASE = 36;\nconst SEG_WIDTH = 4;\nconst SEG_SPACE = BASE ** SEG_WIDTH;\n\nfunction seg(n: number): string {\n return n.toString(BASE).padStart(SEG_WIDTH, \"0\");\n}\n\n/**\n * Default {@link Correlator}. Produces ids of the form\n * `{state[:4]}-{action[:4]}-{4 ms}{4 random}` — 18 characters, lowercase\n * base36.\n *\n * - Prefix carries human-meaningful context (state + action) so operators\n * can identify a workflow at a glance in logs and query results.\n * - The 4-character `Date.now() % 36^4` segment wraps every ~28 minutes,\n * long enough that adjacent inserts in a typical workflow share B-tree\n * pages — index locality, not global sortability, is the goal.\n * - The 4-character random tail gives 1.68M values per ms; collision risk\n * across K=100 concurrent workers is roughly K² / 3.4M per ms.\n *\n * Names shorter than 4 chars are used as-is (no padding) so a state named\n * `Tx` produces `tx-...` rather than `tx00-...`.\n */\nexport const default_correlator: Correlator = ({ state, action }) => {\n const s = state.slice(0, SEG_WIDTH).toLowerCase();\n const a = action.slice(0, SEG_WIDTH).toLowerCase();\n const ts = seg(Date.now() % SEG_SPACE);\n const rnd = seg(randomInt(SEG_SPACE));\n return `${s}-${a}-${ts}${rnd}`;\n};\n\n/**\n * Resolves the correlation id for the close-the-books transaction.\n * Close runs outside any user action, so we synthesize a context with\n * sentinel state/action names — visible in the id when overrides aren't\n * configured.\n *\n * @internal\n */\nexport function close_correlation(\n correlator: Correlator,\n actor: Actor\n): string {\n return correlator({\n state: \"$close\",\n action: \"close\",\n stream: \"$close\",\n actor,\n });\n}\n","/**\n * @module drain-cycle\n * @category Internal\n *\n * Two layers of the drain pipeline:\n *\n * - {@link run_drain_cycle} — pure function for one round-trip of\n * claim → fetch → group → dispatch → ack/block. No orchestrator state.\n * Reusable for property tests and standalone benchmarks.\n *\n * - {@link DrainController} — stateful driver that owns the armed flag,\n * the concurrency lock, and the adaptive lag/lead ratio. Wraps\n * `run_drain_cycle` with the lifecycle decisions Act used to make inline.\n *\n * @internal\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { log } from \"../ports.js\";\nimport type {\n BatchHandler,\n BlockedLease,\n CloseTarget,\n Drain,\n DrainOptions,\n Fetch,\n Lease,\n Logger,\n ReactionPayload,\n Registry,\n SchemaRegister,\n Schemas,\n} from \"../types/index.js\";\nimport type { CircuitBreaker } from \"./circuit-breaker.js\";\nimport { DeferTimer } from \"./defer-timer.js\";\nimport type { DrainOps } from \"./drain.js\";\nimport { compute_lag_lead_ratio } from \"./drain-ratio.js\";\nimport { trace_cycle } from \"./tracing.js\";\n\n/**\n * Outcome of processing a single leased stream — produced by Act's `handle`\n * / `handle_batch` dispatchers, consumed by `run_drain_cycle` to drive ack/block.\n *\n * @internal\n */\nexport type HandleResult = Readonly<{\n lease: Lease;\n handled: number;\n /**\n * Event id at which the ack would land — the last *successful* event\n * id, or `lease.at` when the batch had no work (empty payloads). Named\n * `acked_at` to pair symmetrically with {@link failed_at} and to keep\n * it visually distinct from `Lease.at` (the pre-cycle watermark — same\n * field name across types but a different semantic).\n */\n acked_at: number;\n error?: string;\n block?: boolean;\n /**\n * Wall-clock timestamp (ms since epoch) at which the next attempt on\n * this stream may run. Populated by `_finalize` only on retry paths\n * where the reaction defined `options.backoff`. Undefined means \"no\n * backoff configured\" — drain re-attempts as soon as the lease expires.\n */\n next_attempt_at?: number;\n /**\n * Wall-clock timestamp (ms since epoch) at which this stream should be\n * re-visited. Set by a handler that *defers* instead of acking or\n * failing: the triggering events stay pending (watermark not advanced),\n * `retry` is not bumped (a defer is not a failure), and the drain holds\n * the stream until `defer` elapses, then redelivers so the handler can\n * re-evaluate. This is the timing primitive autoclose rides (#1090);\n * unlike {@link next_attempt_at} (a retry-only backoff), a defer carries\n * no error and never blocks. When present, the result is excluded from\n * ack and block — it neither advances nor terminates the watermark.\n */\n defer?: number;\n /**\n * Close request (#1090). Set when a handler throws `CloseSignal` to retire\n * its stream: the triggering event is acked (so the closing reaction isn't\n * seen as an in-flight consumer by the close-cycle safety guard) and the\n * drain hands this {@link CloseTarget} to the orchestrator's `on_close`,\n * which runs `run_close_cycle`. Carries the optional archiver from the\n * signal. Distinct from {@link defer} (hold for later) — a close advances\n * and retires.\n */\n close?: CloseTarget;\n /**\n * Event id that threw, when a handler error occurred. Distinct from\n * {@link acked_at}: `failed_at = acked_at + 1` in dense streams, but\n * adapters with sparse ids give the trace the exact position. Always\n * set on the per-event error path; absent in batch mode (where no\n * single event id can be attributed to the failure).\n */\n failed_at?: number;\n}>;\n\n/**\n * Per-event reaction dispatcher signature (matches `Act.handle`).\n * @internal\n */\nexport type Handle<TEvents extends Schemas> = (\n lease: Lease,\n payloads: ReactionPayload<TEvents>[]\n) => Promise<HandleResult>;\n\n/**\n * Bulk reaction dispatcher signature (matches `Act.handle_batch`).\n * @internal\n */\nexport type HandleBatch<TEvents extends Schemas> = (\n lease: Lease,\n payloads: ReactionPayload<TEvents>[],\n batchHandler: BatchHandler<TEvents>\n) => Promise<HandleResult>;\n\n/**\n * One drain cycle's results. Returned by {@link run_drain_cycle}; consumed by\n * `Act.drain()` to update lifecycle state, the lag/lead ratio, and emit the\n * `acked` / `blocked` lifecycle events.\n *\n * @internal\n */\nexport type DrainCycle<TEvents extends Schemas> = {\n readonly leased: Lease[];\n readonly fetched: Fetch<TEvents>;\n readonly handled: HandleResult[];\n readonly acked: Lease[];\n readonly blocked: BlockedLease[];\n /** Streams a handler asked to close this cycle (#1090) — handed to `on_close`. */\n readonly closeable: CloseTarget[];\n};\n\n/**\n * Terminal result for a stream whose retry budget was spent without a single\n * attempt ever reaching the block decision — or `undefined` when the stream\n * still has budget.\n *\n * The budget is consulted on the *error* path (`finalize` returns early when\n * a handler didn't throw), so it only terminates handlers that fail loudly. A\n * handler that fails by overrunning its lease never throws: it completes,\n * submits an ack the store drops (`WHERE leased_by = by`), and the next claim\n * bumps `retry` again. `retry` climbs without bound, the watermark never\n * advances, and the side effect re-runs forever — the one outcome\n * `blockOnError` exists to prevent (#1418).\n *\n * The threshold is strictly greater than `maxRetries`, not `>=`, and that is\n * load-bearing. A stream legitimately reaches `retry === maxRetries` on its\n * final attempt, which `finalize` is entitled to run and block only if it\n * fails again. Blocking here at `>=` would take that attempt away and change\n * every error-driven path. At `>` the only way to arrive is with the budget\n * already spent and no attempt having produced an error — a lease lost every\n * single round, which is the stuck stream and nothing else.\n *\n * Gated on `blockOnError` for the same reason `finalize` is: an operator who\n * opted out of blocking chose \"retry forever,\" and that choice holds here too.\n *\n * @internal\n */\nfunction budget_exhausted<TEvents extends Schemas>(\n lease: Lease,\n options: ReactionPayload<TEvents>[\"options\"] | undefined\n): HandleResult | undefined {\n if (!options?.blockOnError || lease.retry <= options.maxRetries)\n return undefined;\n const error = `Blocking ${lease.stream} after ${lease.retry} claims with no acknowledged progress — the lease was lost on every attempt, so the retry budget (${options.maxRetries}) was spent without the handler ever reporting an error. Raise leaseMillis for this handler, then unblock the stream.`;\n log().error(error);\n return { lease, handled: 0, acked_at: lease.at, error, block: true };\n}\n\n/**\n * Run one drain cycle: claim streams, fetch their events, dispatch\n * matching reactions, ack the successes, block the retries-exhausted.\n *\n * Returns `undefined` when nothing was claimed — caller can short-circuit\n * the rest of the drain pass.\n *\n * **Deferred streams** (backoff windows and explicit defers) are excluded\n * upstream by `claim`: their persisted `deferred_at` gates re-dispatch, so\n * they never reach this cycle until the schedule elapses.\n *\n * @internal\n */\nexport async function run_drain_cycle<\n TEvents extends Schemas,\n TActions extends Schemas,\n TSchemaReg extends SchemaRegister<TActions>,\n>(\n ops: DrainOps<TEvents>,\n registry: Registry<TSchemaReg, TEvents, TActions>,\n batch_handlers: Map<string, BatchHandler<TEvents>>,\n handle: Handle<TEvents>,\n handle_batch: HandleBatch<TEvents>,\n lagging: number,\n leading: number,\n eventLimit: number,\n leaseMillis: number,\n /**\n * Emitted as soon as `block` confirms, BEFORE the `ack` that follows.\n * A block is terminal: every adapter gates `block` on `blocked = false`\n * and excludes a blocked stream from `claim`, so it never runs again for\n * that stream. If the emit waited until the end of the cycle, an `ack`\n * failure in between would lose the `blocked` event permanently (#1390).\n */\n on_blocked: (blocked: BlockedLease[]) => void,\n lane?: string\n): Promise<DrainCycle<TEvents> | undefined> {\n // Atomically discover and lease streams (competing consumer pattern)\n const leased = await ops.claim(\n lagging,\n leading,\n randomUUID(),\n leaseMillis,\n lane\n );\n if (!leased.length) return undefined;\n\n // Fetch events for each leased stream. Streams in a backoff window are\n // already excluded here: the store persists `deferred_at` on a due-marked\n // ack and `claim` skips streams whose schedule hasn't elapsed (#1262), so\n // a paced retry never reaches dispatch and no local skip-gate is needed.\n const fetched = await ops.fetch(leased, eventLimit);\n\n // Build a single index keyed by stream — collapses two passes\n // (payloads_map build + per-lease fetched.find) into one Map lookup.\n type FetchEntry = (typeof fetched)[number];\n const fetch_map = new Map<\n string,\n { fetch: FetchEntry; payloads: ReactionPayload<TEvents>[] }\n >();\n\n // compute fetch window max event id\n const fetch_window_at = fetched.reduce(\n (max, { at, events }) => Math.max(max, events.at(-1)?.id || at),\n 0\n );\n\n for (const f of fetched) {\n const { stream, events } = f;\n const payloads = events.flatMap((event) => {\n const register = registry.events[event.name];\n if (!register) return [];\n return [...register.reactions.values()]\n .filter((reaction) => {\n const resolved =\n typeof reaction.resolver === \"function\"\n ? reaction.resolver(event)\n : reaction.resolver;\n return resolved && resolved.target === stream;\n })\n .map((reaction) => ({ ...reaction, event }));\n });\n fetch_map.set(stream, { fetch: f, payloads });\n }\n\n const handled = await Promise.all(\n leased.map((lease) => {\n // fetch() returns one entry per leased stream — fetch_map.get is\n // always defined here (asserted with `!`).\n const entry = fetch_map.get(lease.stream)!;\n // fast-forward watermark using fetched events or window max\n const at = entry.fetch.events.at(-1)?.id || fetch_window_at;\n const { payloads } = entry;\n const exhausted = budget_exhausted(lease, payloads[0]?.options);\n if (exhausted) return Promise.resolve(exhausted);\n const batchHandler = batch_handlers.get(lease.stream);\n if (batchHandler && payloads.length > 0) {\n return handle_batch({ ...lease, at }, payloads, batchHandler);\n }\n return handle({ ...lease, at }, payloads);\n })\n );\n\n // Finalize the cycle in one atomic store call. Every entry advances the\n // watermark to the last event fully handled this cycle, and a deferred or\n // backing-off entry rides the same batch marked with `due` so the store\n // ALSO persists the schedule — advance and defer are independent legs of\n // one ack (#1278). A failed finalize lands nothing — the catch in the\n // controller covers every outcome uniformly. Partial-success-then-block\n // still lands in both `acked` and `blocked` for the same stream — by design.\n //\n // The advance target is `acked_at` (the last fully-handled event) when the\n // batch made progress, and the pre-fetch watermark `floor` (`leased[i].at`,\n // a no-op advance) when it did not — because on a no-progress failure\n // `acked_at` is initialized to the fetch ceiling and would skip the failed\n // event. `leased[i]` pairs with `handled[i]` (Promise.all preserves order),\n // so `floor` is the untouched claim watermark.\n //\n // Deferring past the succeeded prefix (rather than holding the whole batch)\n // is the point: the handled events never re-run on redelivery. A backoff\n // retry carries the climbing `retry` so the budget keeps accruing toward\n // `blockOnError` and the durable cross-worker window (#1262) survives; an\n // explicit defer passes `retry: -1` because a defer is not a failure.\n //\n // `block` runs BEFORE `ack` (#1296). Both stores gate `block` on the lease\n // still being held (`WHERE leased_by = by AND blocked = false`), but `ack`\n // releases the lease (`leased_by = NULL`). A partial-progress-then-block\n // entry (`handled > 0` AND `block: true` — e.g. a `NonRetryableError` on the\n // second event of a batch) is passed to BOTH: `block` marks it poison\n // without touching the watermark, then `ack` advances past the handled\n // prefix and releases the lease. Acking first would release the lease out\n // from under `block`, silently dropping it — the stream would re-run its\n // permanently-failed tail next cycle. Neither store clears the watermark on\n // `block`, so the ordering leaves both legs intact.\n const blocked = await ops.block(\n handled\n .filter(({ block }) => block)\n .map(({ lease, error }) => ({ ...lease, error: error! }))\n );\n\n if (blocked.length) on_blocked(blocked);\n\n const submitted = handled.flatMap((h, i) => {\n const advance = h.handled > 0 ? h.acked_at : leased[i].at;\n return h.defer !== undefined\n ? { ...h.lease, at: advance, due: h.defer, retry: -1 }\n : h.next_attempt_at !== undefined\n ? { ...h.lease, at: advance, due: h.next_attempt_at }\n : h.handled > 0 || !h.error\n ? { ...h.lease, at: h.acked_at }\n : [];\n });\n const acked = await ops.ack(submitted);\n\n // Every adapter gates `ack` on the lease still being held\n // (`WHERE leased_by = by`) — correctly, since that is what stops an\n // evicted holder from regressing a watermark a competitor advanced. But\n // the loss came back as a SHORT RETURN with no error, and nothing compared\n // the two, so a worker whose lease was stolen mid-handler discarded a full\n // round of work with no signal anywhere (#1418).\n //\n // Deferred entries are excluded from ack's return by contract, so they are\n // not \"missing\" — only non-due submissions are counted here.\n const expected = submitted.filter((l) => l.due === undefined).length;\n if (acked.length < expected)\n log().error(\n new Error(\n `drain: ${expected - acked.length} of ${expected} acks were dropped — the lease was taken by another worker mid-handler. That work will be redelivered (at-least-once), but persistent drops mean leaseMillis is too short for this handler.`\n )\n );\n\n // Collect close requests (#1090). A close result was already acked above\n // (its event made progress, `defer === undefined`), which advances the\n // requesting reaction past the terminal event so the close-cycle safety\n // guard doesn't count it as an in-flight consumer. The orchestrator's\n // `on_close` runs the actual `run_close_cycle`.\n const closeable = handled\n .filter((h) => h.close !== undefined)\n .map((h) => h.close!);\n\n return { leased, fetched, handled, acked, blocked, closeable };\n}\n\n/**\n * Empty drain result returned when the controller short-circuits (not\n * armed, locked out by a concurrent caller, claim returned nothing,\n * cycle threw).\n *\n * @internal\n */\nconst EMPTY_DRAIN: Drain<Schemas> = {\n fetched: [],\n leased: [],\n acked: [],\n blocked: [],\n};\n\n/**\n * Dependencies the {@link DrainController} needs from the orchestrator.\n * The lifecycle event sinks (`on_acked` / `on_blocked`) are callbacks so\n * this module doesn't reach back into Act's emitter.\n *\n * @internal\n */\nexport type DrainControllerDeps<\n TEvents extends Schemas,\n TActions extends Schemas,\n TSchemaReg extends SchemaRegister<TActions>,\n> = {\n readonly logger: Logger;\n readonly ops: DrainOps<TEvents>;\n readonly registry: Registry<TSchemaReg, TEvents, TActions>;\n readonly batch_handlers: Map<string, BatchHandler<TEvents>>;\n readonly handle: Handle<TEvents>;\n readonly handle_batch: HandleBatch<TEvents>;\n readonly on_acked: (acked: Lease[]) => void;\n readonly on_blocked: (blocked: BlockedLease[]) => void;\n /**\n * Close requested by a reaction (#1090). The controller calls this with the\n * cycle's {@link CloseTarget}s after acks/blocks land; the orchestrator wires\n * it to its `run_close_cycle` machinery (same path as `app.close`). Awaited so\n * a slow close doesn't overlap the next cycle's claim on the controller.\n */\n readonly on_close: (targets: CloseTarget[]) => Promise<void>;\n /**\n * Shared, orchestrator-owned circuit breaker (ACT-984). Trips after\n * repeated store failures so the drain loop stops hammering a down\n * backend; closed/half-open let attempts through. It also surfaces each\n * failure (via its own `on_error`, wired by the orchestrator to the\n * `error` lifecycle event), so callers just `failed(now, error)`.\n */\n readonly breaker: CircuitBreaker;\n /**\n * Scope runner (#1191). The per-lane worker (`start`) ticks outside\n * any caller frame, so its `drain()` must be re-wrapped in the Act's\n * `_scoped` bag or `store()`/`cache()` resolve to the singleton for a\n * scoped Act. The orchestrator always threads its `_scoped` (identity\n * for a non-scoped Act), so it's required.\n */\n readonly run_scoped: <T>(fn: () => Promise<T>) => Promise<T>;\n /** Lane this controller drains. Undefined = spans all lanes (legacy single-controller). */\n readonly lane?: string;\n /** Per-lane defaults applied when caller doesn't override via DrainOptions. */\n readonly defaults?: {\n readonly streamLimit?: number;\n readonly eventLimit?: number;\n readonly leaseMillis?: number;\n };\n};\n\n/**\n * Stateful driver around {@link run_drain_cycle}. Owns:\n *\n * - `_armed` — has any commit / reset / cold-start signaled work to do?\n * - `_locked` — concurrent-call guard (overlapping `drain()` calls return\n * an empty result instead of running twice)\n * - `_ratio` — adaptive lag-to-lead frontier split, updated per cycle\n *\n * The orchestrator owns commits, lifecycle emission, and `arm()` triggers\n * — the controller owns everything between those edges.\n *\n * @internal\n */\nexport class DrainController<\n TEvents extends Schemas,\n TActions extends Schemas,\n TSchemaReg extends SchemaRegister<TActions>,\n> {\n private _armed = false;\n private _locked = false;\n private _ratio = 0.5;\n /**\n * Per-stream re-visit schedule (#1090): `stream → next visit` (ms since\n * epoch). Holds both retry backoff (`HandleResult.next_attempt_at`) and the\n * `defer` outcome; cleared on successful ack or terminal block. Lives in\n * process memory — per-worker pacing by design (see {@link BackoffOptions}\n * for the multi-worker trade-off). Its wake re-arms drain at the earliest\n * pending visit.\n */\n private readonly _defer = new DeferTimer(() => {\n this._armed = true;\n });\n /** Worker timer (ACT-1103). Set when `start()` is active, undefined otherwise. */\n private _worker: ReturnType<typeof setTimeout> | undefined;\n private _stopped = false;\n\n private readonly _deps: DrainControllerDeps<TEvents, TActions, TSchemaReg>;\n\n constructor(deps: DrainControllerDeps<TEvents, TActions, TSchemaReg>) {\n this._deps = deps;\n }\n\n /**\n * Signal that a commit (or reset / cold-start) may have produced work.\n * Subsequent `drain()` calls will run the pipeline; once the pipeline\n * settles to no-progress, the controller disarms itself.\n */\n arm(): void {\n this._armed = true;\n }\n\n /**\n * Re-seed a persisted defer schedule into the process-local timer at cold\n * start (#1221). The `_defer` map lives in worker memory and is empty\n * after a restart; a stream deferred to a future due-time (e.g. an idle\n * autoclose aggregate) is durable in the store's `deferred_at` but has\n * nothing in memory to re-arm the drain at the due-time. The orchestrator\n * reads the persisted `deferred_at` for this controller's lane and calls\n * this to park the stream + (re)schedule the shared wake — so the drain\n * re-arms at the due-time with no intervening commit. `schedule()`\n * collapses many seeds into one timer, so callers may seed in a loop and\n * let the earliest due-time win.\n */\n seed_defer(stream: string, at: number): void {\n this._defer.set(stream, at);\n this._defer.schedule();\n }\n\n /** Read-only flag — true while a commit / reset is unprocessed. */\n get armed(): boolean {\n return this._armed;\n }\n\n /** Lane this controller drains (undefined = legacy single-lane span). */\n get lane(): string | undefined {\n return this._deps.lane;\n }\n\n /**\n * Start a per-lane worker that drains at the lane's `cycleMs`\n * cadence (ACT-1103). When armed, the worker calls `drain()` on every\n * tick and re-schedules; when not armed, it still re-schedules at\n * `cycleMs` so a future `arm()` is picked up on the next tick.\n *\n * The setTimeout chain uses `unref()` so it doesn't keep the process\n * alive on its own.\n */\n start(cycleMs: number): void {\n if (this._worker || this._stopped) return;\n // `drain()` swallows its own errors and returns EMPTY_DRAIN, so the\n // tick is exception-free by contract. The post-drain `_stopped`\n // check prevents re-scheduling after `stop()` was called mid-tick;\n // an already-queued timer that fires before `clearTimeout()` lands\n // will run at most one extra drain (drain is idempotent against\n // a non-armed controller and self-disarms when settled).\n const run = this._deps.run_scoped;\n const tick = async () => {\n if (this._armed) await run(() => this.drain());\n if (this._stopped) return;\n this._worker = setTimeout(tick, cycleMs);\n this._worker.unref();\n };\n this._worker = setTimeout(tick, cycleMs);\n this._worker.unref();\n }\n\n /** Stop the per-lane worker. Idempotent. */\n stop(): void {\n this._stopped = true;\n if (this._worker) {\n clearTimeout(this._worker);\n this._worker = undefined;\n }\n // Drop any pending re-visit wake — the parked set is process-local and\n // rebuilt from the log on the next start (#1090).\n this._defer.stop();\n }\n\n /** Run one drain pass. Short-circuits when not armed or already running. */\n async drain(options: DrainOptions = {}): Promise<Drain<TEvents>> {\n if (!this._armed) return EMPTY_DRAIN as Drain<TEvents>;\n if (this._locked) return EMPTY_DRAIN as Drain<TEvents>;\n // Circuit open: the store is failing, skip the claim entirely so we\n // don't hammer a down backend. `_armed` stays set, so the next tick\n // after the cooldown (half-open) retries.\n if (this._deps.breaker.state(Date.now()) === \"open\")\n return EMPTY_DRAIN as Drain<TEvents>;\n\n const d = this._deps.defaults ?? {};\n // Per-lane config wins over caller options (ACT-1103). The whole\n // point of `withLane({leaseMillis: 30_000})` is to give the slow\n // lane its own budget — a caller-level drain({leaseMillis}) would\n // erase it. Caller options apply only when the lane didn't pin a\n // value.\n const streamLimit = d.streamLimit ?? options.streamLimit ?? 10;\n const eventLimit = d.eventLimit ?? options.eventLimit ?? 10;\n const leaseMillis = d.leaseMillis ?? options.leaseMillis ?? 10_000;\n\n try {\n this._locked = true;\n const lagging = Math.ceil(streamLimit * this._ratio);\n const leading = streamLimit - lagging;\n\n const cycle = await run_drain_cycle(\n this._deps.ops,\n this._deps.registry,\n this._deps.batch_handlers,\n this._deps.handle,\n this._deps.handle_batch,\n lagging,\n leading,\n eventLimit,\n leaseMillis,\n (b) => this._deps.on_blocked(b),\n this._deps.lane\n );\n\n // The store responded (claim/fetch/ack+defer/block all succeeded) —\n // reset the breaker even when there was no work to do. A failed\n // finalize never reaches here: `Store.ack` applies watermarks and\n // defer schedules atomically, so it either all landed or the\n // whole cycle threw into the catch below and nothing did.\n if (!cycle) {\n // claim() returned no leases — fully caught up\n this._deps.breaker.passed();\n this._armed = false;\n return EMPTY_DRAIN as Drain<TEvents>;\n }\n\n const { leased, fetched, handled, acked, blocked, closeable } = cycle;\n\n // Cycle-level trace (ACT-1103) — one log line per drain pass:\n // claim + fetch + outcomes folded together so the operator sees\n // a single atomic narrative for each cycle. No-op when the\n // logger isn't at trace level.\n trace_cycle(this._deps.logger, leased, fetched, handled, acked, blocked);\n\n // Adapt next cycle's frontier split to where the pressure is.\n this._ratio = compute_lag_lead_ratio(handled, lagging, leading);\n\n // Refresh per-stream re-visit state from this cycle's outcomes.\n // Successful acks and terminal blocks both clear the window;\n // retry-not-block results carry a `next_attempt_at` set by `_finalize`,\n // and deferred results carry a `defer` due-time (#1090). Both park the\n // stream in `_defer` so the shared wake timer re-arms drain at the\n // earliest pending visit. `handle` already reconciles a stream's\n // reactions into a single result per cycle, so the value written here\n // is authoritative for the stream — a plain overwrite, not a merge.\n for (const lease of acked) this._defer.delete(lease.stream);\n for (const lease of blocked) this._defer.delete(lease.stream);\n for (const h of handled) {\n const next = h.defer ?? (h.block ? undefined : h.next_attempt_at);\n if (next !== undefined) this._defer.set(h.lease.stream, next);\n }\n if (this._defer.size > 0) this._defer.schedule();\n\n // Lifecycle sinks are contained individually, mirroring the\n // `notified` handler in `act.ts`. The durable work is already\n // committed by this point, so a throwing listener must not unwind\n // into the store-error `catch` below: that would report a store\n // failure that never happened, return an empty Drain, and — because\n // `block` is guarded on `blocked = false` and a blocked stream is\n // excluded from `claim` — permanently lose the `blocked` event and\n // any reaction-requested close. Listener containment itself lives in\n // `Act.emit`, which guards each listener individually (#1437) — the\n // sinks here are plain calls.\n if (acked.length) this._deps.on_acked(acked);\n // Run reaction-requested closes after acks land (#1090) — the close\n // targets were acked above, so the close-cycle guard sees the requesting\n // reaction as caught up. Awaited so a slow close doesn't overlap the\n // next claim.\n // NOT contained: `on_close` runs the close machinery (load,\n // tombstone, archive, truncate), not an emit. A StoreError raised in\n // there is a real store failure and must reach the breaker via the\n // catch below, or an outage silently bricks streams while the\n // breaker records a success (#1388). The `closed` EMIT is contained\n // on the Act side, which is the only listener risk on this path.\n if (closeable.length) await this._deps.on_close(closeable);\n\n // Recorded after `on_close` so a cycle whose close failed is never\n // counted as a store success (#1388).\n this._deps.breaker.passed();\n\n // Disarm only when fully caught up. Errors keep the flag set so\n // retries flow through the next drain.\n const has_errors = handled.some(({ error }) => error);\n if (!acked.length && !blocked.length && !has_errors) this._armed = false;\n\n return { fetched, leased, acked, blocked };\n } catch (error) {\n // A store op threw (StoreError, or any failure mid-cycle). Record it\n // on the breaker, which logs it and surfaces the `error` lifecycle\n // event. `_armed` stays set so the breaker's retry re-attempts after\n // the cooldown. EMPTY_DRAIN keeps the worker tick exception-free.\n this._deps.breaker.failed(Date.now(), error);\n return EMPTY_DRAIN as Drain<TEvents>;\n } finally {\n this._locked = false;\n }\n }\n}\n","/**\n * @module defer-timer\n * @category Internal\n *\n * The shared \"next visit time\" primitive (#1090). A `DeferTimer` holds a\n * `stream → due-time` map and a single collapsed wake timer: it parks\n * streams that should be re-visited later and fires one `on_wake` callback\n * at the earliest pending due-time, garbage-collecting the entries that have\n * come due.\n *\n * Two consumers ride it:\n *\n * - the {@link \"drain-cycle\".DrainController} — for per-reaction backoff (a\n * retry's `next_attempt_at`) and, once handlers can express it, the\n * `defer` outcome that holds a stream pending without advancing the\n * watermark or bumping `retry`.\n * - the autoclose controller — to schedule its next eligibility check at the\n * precise time an `after`-style cooldown elapses, instead of a blind\n * fixed-interval sweep.\n *\n * Lives in process memory, per worker — the same per-worker pacing trade-off\n * documented for backoff. Durability comes from the data the due-time is\n * *derived* from (an un-advanced watermark, an event's `created` timestamp),\n * not from the map. A restart empties the map, so the cold-start rebuild is\n * explicit: `CorrelateCycle.init` seeds each still-future `deferred_at` back\n * onto the owning lane's timer via {@link \"drain-cycle\".DrainController.seed_defer}\n * (#1221), so an idle deferred stream re-arms at its due-time with no\n * intervening commit.\n *\n * @internal\n */\n\n/**\n * A min-heap-free scheduler over a small `stream → due-time` map. The maps\n * are bounded by the worker's claim/stream limits, so a linear scan for the\n * earliest entry is cheaper than maintaining a heap.\n *\n * @internal\n */\n\n/**\n * Node's `setTimeout` delay is a 32-bit signed int (~24.8 days). A larger\n * delay overflows and fires immediately, so we cap at this and re-arm.\n *\n * @internal\n */\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\n\nexport class DeferTimer {\n private readonly _due = new Map<string, number>();\n private _timer: ReturnType<typeof setTimeout> | undefined;\n private readonly _on_wake: () => void;\n\n /**\n * @param on_wake - invoked once each time the earliest due-time elapses,\n * after the come-due entries have been removed. Consumers use it to\n * re-arm their loop (the drain sets its `armed` flag; autoclose runs a\n * tick).\n */\n constructor(on_wake: () => void) {\n this._on_wake = on_wake;\n }\n\n /** Number of currently parked streams. */\n get size(): number {\n return this._due.size;\n }\n\n /**\n * True while `stream` is parked with a due-time still in the future.\n * Consumers skip work for deferred streams until their window elapses.\n */\n is_deferred = (stream: string): boolean => {\n const next = this._due.get(stream);\n return next !== undefined && next > Date.now();\n };\n\n /**\n * Park `stream` for a re-visit at `at` (ms since epoch). A plain\n * overwrite: the caller computes the authoritative next-visit for the\n * stream (the drain's `handle` already reconciles a stream's reactions\n * into one result per cycle), so there is no stale value to merge against.\n */\n set(stream: string, at: number): void {\n this._due.set(stream, at);\n }\n\n /** Drop `stream` from the parked set (e.g. on a successful ack or block). */\n delete(stream: string): void {\n this._due.delete(stream);\n }\n\n /**\n * (Re)schedule the wake timer at the earliest pending due-time. Idempotent\n * — collapses many parked streams into a single timer. A no-op clears any\n * pending timer when the map is empty.\n *\n * The timer is `unref()`-ed so pending re-visits never keep the process\n * alive on their own.\n */\n schedule(): void {\n if (this._timer) clearTimeout(this._timer);\n if (this._due.size === 0) {\n this._timer = undefined;\n return;\n }\n let earliest = Number.POSITIVE_INFINITY;\n for (const t of this._due.values()) if (t < earliest) earliest = t;\n // Clamp to setTimeout's 32-bit ceiling (~24.8 days). A longer due-time\n // (e.g. a 90-day autoclose cooldown) would otherwise overflow and Node\n // fires it immediately, busy-looping. Instead we wake at the ceiling and\n // re-arm: the GC below keeps the still-future entry, `on_wake` re-schedules\n // for the remaining span, and (for persisted defers) `claim` skips the\n // stream until its real due-time anyway.\n const delay = Math.min(\n Math.max(0, earliest - Date.now()),\n MAX_TIMER_DELAY_MS\n );\n this._timer = setTimeout(() => {\n this._timer = undefined;\n // Garbage-collect the entries that have come due so the consumer's\n // next pass sees them as active again.\n const now = Date.now();\n let came_due = false;\n for (const [stream, at] of this._due)\n if (at <= now) {\n this._due.delete(stream);\n came_due = true;\n }\n this._on_wake();\n // Premature ceiling clamp: nothing came due, yet entries remain — the\n // earliest due-time was past the 32-bit `setTimeout` ceiling, so this\n // wake fired early. The consumer's `on_wake` won't re-arm (the drain's\n // just sets its armed flag, and its next pass early-returns while the\n // stream is still store-excluded), so the primitive must self-re-arm or\n // a >ceiling defer/cooldown loses its precise wake (#1288). A normal wake\n // (something came due) leaves re-arming to the consumer, preserving the\n // fire-once-per-schedule model.\n if (!came_due && this._due.size > 0) this.schedule();\n }, delay);\n this._timer.unref();\n }\n\n /** Cancel any pending wake timer. Idempotent. Leaves the parked set intact. */\n stop(): void {\n if (this._timer) {\n clearTimeout(this._timer);\n this._timer = undefined;\n }\n }\n}\n","/**\n * @module drain-ratio\n * @category Internal\n *\n * Adaptive lag-to-lead ratio for the dual-frontier drain strategy.\n *\n * The orchestrator splits its per-cycle stream budget between two frontiers:\n *\n * - **lagging** — newly subscribed or behind streams catching up.\n * - **leading** — actively-processing streams at the head of the log.\n *\n * After each cycle, this helper looks at how many events were actually\n * handled in each frontier and shifts the next cycle's split toward\n * whichever frontier had the higher per-stream throughput. The result is\n * clamped to `[0.2, 0.8]` so neither frontier can be starved.\n *\n * @internal\n */\n\nimport type { HandleResult } from \"./drain-cycle.js\";\n\n/** Floor / ceiling for the lag-to-lead ratio so neither frontier starves. */\nconst RATIO_MIN = 0.2;\nconst RATIO_MAX = 0.8;\n/** Default ratio when no events were handled in either frontier. */\nconst RATIO_DEFAULT = 0.5;\n\n/**\n * Compute the next lag-to-lead ratio from the cycle's handled events and\n * the frontier sizes used to claim them. Returns `RATIO_DEFAULT` when no\n * progress was made (nothing to base a decision on).\n */\nexport function compute_lag_lead_ratio(\n handled: ReadonlyArray<HandleResult>,\n lagging: number,\n leading: number\n): number {\n let lagging_handled = 0;\n let leading_handled = 0;\n for (const { lease, handled: count } of handled) {\n if (lease.lagging) lagging_handled += count;\n else leading_handled += count;\n }\n const lagging_avg = lagging > 0 ? lagging_handled / lagging : 0;\n const leading_avg = leading > 0 ? leading_handled / leading : 0;\n const total = lagging_avg + leading_avg;\n if (total === 0) return RATIO_DEFAULT;\n return Math.max(RATIO_MIN, Math.min(RATIO_MAX, lagging_avg / total));\n}\n","/**\n * @module drain\n * @category Internal\n *\n * Pipeline operations consumed by the drain/correlate loop. Each op is a\n * single async step the orchestrator invokes per drain cycle:\n *\n * - `claim` — atomically discover and lock streams for processing\n * - `fetch` — read events for each leased stream\n * - `ack` — release leases for successfully handled streams\n * - `block` — flag leases that exceeded the retry budget\n * - `subscribe` — register newly correlated streams with the store\n *\n * This module exposes only the bare implementations as plain async functions,\n * mirroring the shape of {@link \"event-sourcing\"}. Trace decoration is\n * layered on top in {@link \"tracing\"} and selected by the orchestrator at\n * construction time. No tracing imports here.\n *\n * @internal\n */\n\nimport { store } from \"../ports.js\";\nimport type {\n BlockedLease,\n Committed,\n Fetch,\n Lease,\n Schemas,\n} from \"../types/index.js\";\nimport { is_literal_source } from \"../utils.js\";\n\n/** @internal */\nexport interface DrainOps<TEvents extends Schemas> {\n claim: typeof claim;\n fetch: typeof fetch<TEvents>;\n ack: typeof ack;\n block: typeof block;\n subscribe: typeof subscribe;\n}\n\nexport const claim = (\n lagging: number,\n leading: number,\n by: string,\n millis: number,\n lane?: string\n): Promise<Lease[]> => store().claim(lagging, leading, by, millis, lane);\n\nexport async function fetch<TEvents extends Schemas>(\n leased: Lease[],\n eventLimit: number\n): Promise<Fetch<TEvents>> {\n return Promise.all(\n leased.map(async ({ stream, source, at, lagging }) => {\n const events: Committed<TEvents, keyof TEvents>[] = [];\n // A literal `source` fetches with `stream_exact` so an exact name\n // like \"s1\" reads only \"s1\" — never a sibling prefix \"s12\". A\n // pattern source (e.g. `^(A|B)$`) stays a regex query, matching the\n // same streams the has-work probe claimed it for.\n const stream_exact =\n source !== undefined && is_literal_source(source) ? true : undefined;\n await store().query<TEvents>((e) => events.push(e), {\n stream: source,\n stream_exact,\n after: at,\n limit: eventLimit,\n });\n return { stream, source, at, lagging, events } as const;\n })\n );\n}\n\n// Finalize: acks and defers in one atomic store call. Leases\n// carrying `due` are deferred, the rest acked — a failed finalize lands\n// nothing, and redelivery covers every outcome uniformly.\nexport const ack = (leases: Lease[]): Promise<Lease[]> => store().ack(leases);\n\nexport const block = (leases: BlockedLease[]): Promise<BlockedLease[]> =>\n store().block(leases);\n\nexport const subscribe = (\n streams: Array<{\n stream: string;\n source?: string;\n priority?: number;\n lane?: string;\n }>\n): Promise<{ subscribed: number; watermark: number }> =>\n store().subscribe(streams);\n","/**\n * @module event-sourcing\n * @category Internal\n *\n * Pure event-sourcing primitives: `snap` persists state checkpoints, `load`\n * reconstructs state by folding events through reducers, and `action`\n * validates an action, runs invariants, emits events, and commits them\n * atomically. `tombstone` commits the close-the-books guard with optimistic\n * concurrency.\n *\n * These are the bare implementations — observability is layered on top in\n * {@link \"tracing\"} and wired by the orchestrator at construction time.\n * No tracing imports here, no module-level mutable state.\n *\n * @internal\n */\n\nimport { type Patch, patch } from \"@rotorsoft/act-patch\";\nimport { cache, log, SNAP_EVENT, store, TOMBSTONE_EVENT } from \"../ports.js\";\nimport {\n ConcurrencyError,\n InvariantError,\n StreamClosedError,\n} from \"../types/errors.js\";\nimport type {\n Committed,\n Correlator,\n DoOptions,\n Emitted,\n EventMeta,\n EventSource,\n LoadTarget,\n ScanOptions,\n ScanResult,\n Schema,\n Schemas,\n Snapshot,\n State,\n Target,\n} from \"../types/index.js\";\nimport { sleep, validate } from \"../utils.js\";\nimport { compute_backoff_delay } from \"./backoff.js\";\nimport { default_correlator } from \"./correlator.js\";\n\n/**\n * The reduction pipeline names three distinct things, and each word means\n * exactly one of them:\n *\n * - a **reducer** is a state's `.patch()` handler — it takes one event and\n * returns a {@link Patch} *partial*;\n * - a **patch step** ({@link bare_patch} / {@link validating_patch}) merges\n * that partial into the current state, yielding the next full state;\n * - the **fold** is the loop that applies the patch step across a stream's\n * events (the reader loop in {@link load} / {@link action}, and the\n * projection engine in {@link \"projection-fold\"}).\n *\n * `PatchFn` is the per-event patch step. The fold loop calls one of two\n * implementations, selected **once** at construction (in\n * {@link \"tracing\".build_es}) — never branched per event:\n *\n * - {@link bare_patch} — the default. Literally `patch(state, partial)`,\n * no wrapper. This is the pre-ACT-1238 hot path, byte-for-byte.\n * - {@link validating_patch} — the opt-in `ActOptions.validateFoldedState`\n * path. Merges, then parses the merged full state against the state's\n * declared Zod schema.\n *\n * The `me`/`event` arguments are unused by the bare implementation but\n * carried on the shared signature so the fold loop is call-shape-identical\n * regardless of which patch step was selected — the validating\n * implementation needs them to name the failing reduction.\n *\n * @internal\n */\nexport type PatchFn = <\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n me: State<TState, TEvents, TActions>,\n state: TState,\n partial: Readonly<Patch<TState>>,\n event: Committed<TEvents, keyof TEvents>\n) => TState;\n\n/**\n * The default patch step: a bare `patch()` merge with no wrapper and no\n * branch. The off-path is byte-for-byte the pre-ACT-1238 reduction, so an\n * app that leaves `validateFoldedState` off pays nothing — not even a\n * comparison.\n *\n * @internal\n */\nexport const bare_patch: PatchFn = (_me, state, partial) =>\n patch(state, partial) as typeof state;\n\n/**\n * The opt-in patch step (ACT-1238): merge the partial into state, then\n * parse the merged full state against the owning state's declared Zod\n * schema. A reducer that produces schema-violating state (the calculator\n * divide-by-zero NaN class, #1230) fails here, at the triggering event,\n * instead of propagating and surfacing hops later as a confusing\n * downstream error.\n *\n * The `target` string names the state and the triggering event\n * (`\"<state>.<event>#<id>\"`) so the resulting {@link ValidationError}\n * points straight at the reduction that produced bad state. A debugging /\n * CI aid, not a production guard — selected only when the operator opts\n * in.\n *\n * @internal\n */\nexport const validating_patch: PatchFn = (me, state, partial, event) => {\n const next = patch(state, partial) as typeof state;\n return validate(\n `${me.name}.${String(event.name)}#${event.id}`,\n next,\n me.state\n );\n};\n\n/**\n * Default per-batch row count for the {@link scan} pagination loop\n * (ACT-1133). Callers override via {@link ScanOptions.batch_size}.\n *\n * @internal\n */\nconst DEFAULT_BATCH = 500;\n\n/**\n * Internal action signature seen by the orchestrator — the {@link Correlator}\n * is bound at `build_es` time, so callers don't pass it through.\n *\n * @internal\n */\nexport type BoundAction = <\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TKey extends keyof TActions,\n>(\n me: State<TState, TEvents, TActions>,\n action: TKey,\n target: Target,\n payload: Readonly<TActions[TKey]>,\n options?: DoOptions<TEvents>\n) => Promise<Snapshot<TState, TEvents>[]>;\n\n/** @internal */\nexport interface EsOps {\n snap: typeof snap;\n load: typeof load;\n action: BoundAction;\n tombstone: typeof tombstone;\n}\n\n/**\n * Event sourcing utilities for snapshotting, loading, and committing actions/events.\n * Used internally by Act and state machines.\n */\n\n/**\n * Saves a snapshot of the state to the store.\n *\n * Snapshots are used to optimize state reconstruction for aggregates with long event streams.\n *\n * @template TState The type of state\n * @template TEvents The type of events\n * @param snapshot The snapshot to save\n * @returns Promise that resolves when the snapshot is saved\n *\n * @example\n * await snap(snapshot);\n */\nexport async function snap<TState extends Schema, TEvents extends Schemas>(\n snapshot: Snapshot<TState, TEvents>\n): Promise<Committed<TEvents, keyof TEvents> | undefined> {\n const { id, stream, name, meta, version } = snapshot.event!;\n try {\n const [committed] = await store().commit(\n stream,\n [{ name: SNAP_EVENT, data: snapshot.state }],\n {\n correlation: meta.correlation,\n causation: { event: { id, name: name as string, stream } },\n },\n version // IMPORTANT! - state events are committed right after the snapshot event\n );\n return committed as Committed<TEvents, keyof TEvents>;\n } catch (error) {\n // Swallow by design — a failed snapshot must never fail the action.\n // But surface an operator signal: a persistently failing snapshot\n // write silently degrades every cold start to full replay.\n const reason = error instanceof Error ? error.message : String(error);\n log().warn(\n `Snapshot write failed on stream \"${stream}\": ${reason} — cold starts will replay full history until snapshots succeed.`\n );\n }\n}\n\n/**\n * Commits a tombstone event with optimistic concurrency, returning the\n * committed record on success or `undefined` if the stream moved past\n * `expectedVersion` (concurrent write detected). Other store errors\n * propagate.\n *\n * Used by `close()` to guard a stream while archive/truncate runs:\n * subsequent `action()` calls see the tombstone at head and reject with\n * {@link StreamClosedError} until the close completes.\n *\n * @internal\n */\nexport async function tombstone(\n stream: string,\n expectedVersion: number,\n correlation: string\n): Promise<Committed<Schemas, keyof Schemas> | undefined> {\n try {\n const [committed] = await store().commit(\n stream,\n [{ name: TOMBSTONE_EVENT, data: {} }],\n { correlation, causation: {} },\n expectedVersion\n );\n return committed;\n } catch (error) {\n if (error instanceof ConcurrencyError) return undefined;\n throw error;\n }\n}\n\n/**\n * Per-event blocker check. Categories:\n *\n * - **Negative `version`** — versions are unsigned in the framework\n * contract.\n * - **Malformed `created`** — `event.created` must be a valid Date\n * instance. Restore sources stream parsed events; the orchestrator\n * trusts the caller's iterator did the parsing.\n *\n * Cross-event invariants (duplicate ids, per-stream version gaps) are\n * not the validator's job — DB `UNIQUE(stream, version)` catches\n * duplicates at commit time, and gap detection is a caller-specific\n * policy (partial backups intentionally have gaps).\n *\n * Extension point: per-event Zod schema validation against the active\n * registry will land here — the source-side check is the right layer\n * for it (catches malformed payloads before the sink transaction\n * opens), and adding it keeps the per-event blocker contract in one\n * place.\n *\n * @internal\n */\nfunction is_valid(event: Committed<Schemas, keyof Schemas>): boolean {\n if (event.version < 0) return false;\n if (!(event.created instanceof Date) || Number.isNaN(event.created.getTime()))\n return false;\n return true;\n}\n\n/**\n * Scan a restore source event by event. Owns pagination, validation,\n * the `drop_snapshots` filter, the `on_progress` callback, and the\n * causation remap; adapters supply only the per-event insert\n * `callback` via the driver pattern (see {@link Store.restore}).\n *\n * Walks the source in chunks of {@link BATCH} via the existing\n * `EventSource.query` interface — `limit: BATCH` and `after: <last\n * id seen>` per batch (ACT-1133). Stores that respect `limit`\n * (`PostgresStore`) return at most `BATCH` rows per call; sources\n * that ignore the filter (`CsvFile`) stream everything in one call\n * and the loop exits after the first batch when `got > BATCH`. The\n * source's own per-event `await Promise.resolve(callback(event))`\n * provides backpressure — no separate mailbox needed.\n *\n * Throws on the first invalid event (negative version, malformed\n * `created`) with the running index in the message.\n *\n * Returns the partial {@link ScanResult} (without `duration_ms`)\n * — {@link Act.restore} wraps the call with its own timing so the\n * duration covers transaction setup and commit, not just iteration.\n *\n * @internal\n */\nexport async function scan(\n source: EventSource,\n opts: ScanOptions = {},\n callback?: (event: Committed<Schemas, keyof Schemas>) => Promise<number>\n): Promise<Omit<ScanResult, \"duration_ms\">> {\n const {\n drop_snapshots = false,\n drop_closed_streams = false,\n on_progress,\n event_migrations,\n stream_rename,\n } = opts;\n const limit = opts.batch_size ?? DEFAULT_BATCH;\n const id_map = new Map<number, number>();\n let kept = 0;\n let dropped_snaps = 0;\n let dropped_closed = 0;\n let migrated_count = 0;\n let processed = 0;\n let at: number | undefined;\n\n // Pre-pass for `drop_closed_streams` (ACT-1126). Walk the source\n // once with a tombstone-name filter to collect closed streams. PG\n // honors the filter and only the tombstone events come back; sources\n // that ignore the filter (CsvFile) stream all events but we cheaply\n // pick out the tombstones in the callback. Either way the cost is\n // one extra walk, paid only when the operator opts in.\n const closed_streams = new Set<string>();\n if (drop_closed_streams) {\n await source.query<Schemas>(\n (e) => {\n if (e.name === TOMBSTONE_EVENT) closed_streams.add(e.stream);\n },\n { names: [TOMBSTONE_EVENT] }\n );\n }\n\n // Probe the source for the highest id once up front. On indexed\n // stores (PostgresStore, SqliteStore) `{ backward: true, limit: 1 }`\n // is an index-only seek — O(1) on the (id) index. Sources that\n // ignore the filter (CsvFile) stream every event from this one\n // call; we detect that via the returned count and leave max_id\n // undefined rather than reporting an unreliable value.\n let max_id: number | undefined;\n const probed = await source.query<Schemas>(\n (e) => {\n max_id = e.id;\n },\n { backward: true, limit: 1 }\n );\n if (probed !== 1) max_id = undefined;\n\n while (true) {\n let got = 0;\n let id: number | undefined;\n\n await source.query<Schemas>(\n async (event) => {\n got++;\n id = event.id;\n processed++;\n if (!is_valid(event))\n throw new Error(`Invalid event at index ${processed}`);\n if (on_progress) on_progress({ processed, id: event.id, max_id });\n if (drop_snapshots && event.name === SNAP_EVENT) {\n dropped_snaps++;\n return;\n }\n if (\n closed_streams.has(event.stream) &&\n event.name !== TOMBSTONE_EVENT\n ) {\n // Drop pre-close events but KEEP the tombstone — it's what\n // makes the stream \"closed\" in the rebuilt store. Without\n // it, a future `app.do(...)` against this stream name would\n // succeed because nothing gates it.\n dropped_closed++;\n return;\n }\n // Migration overlay (ACT-1126): rename + schema-guarded data\n // transform, then optional stream rename. Applied BEFORE the\n // causation remap so the id_map (keyed by source id) stays\n // valid and migrated events land at the new name/data with\n // their causation chains intact.\n let migrated: typeof event = event;\n const migration = event_migrations?.[event.name as string];\n if (migration) {\n const old_data = migration.from_schema.parse(event.data);\n const new_data = migration.migrate(old_data);\n migration.to_schema.parse(new_data);\n migrated = {\n ...event,\n name: migration.to as typeof event.name,\n data: new_data as any,\n };\n migrated_count++;\n }\n if (stream_rename) {\n const renamed = stream_rename(migrated.stream);\n if (renamed !== migrated.stream)\n migrated = { ...migrated, stream: renamed };\n }\n if (!callback) {\n kept++;\n return;\n }\n // Causation remap — rewrite `meta.causation.event.id` to the\n // new id space if the source pointed at an earlier event's\n // old id.\n let remapped = migrated;\n const caused_by = migrated.meta.causation.event?.id;\n if (caused_by !== undefined) {\n const new_caused_by = id_map.get(caused_by);\n if (new_caused_by !== undefined && new_caused_by !== caused_by) {\n // Spread `migrated`, not the original `event` (ACT-1192).\n // Migration + stream_rename already ran above; rebuilding from\n // `event` here would revert the new name/data/stream for any\n // event whose causation id shifted — silently undoing the\n // migration for most rows after the first id shift.\n remapped = {\n ...migrated,\n meta: {\n ...migrated.meta,\n causation: {\n ...migrated.meta.causation,\n event: {\n ...migrated.meta.causation.event!,\n id: new_caused_by,\n },\n },\n },\n };\n }\n }\n const new_id = await callback(remapped);\n id_map.set(event.id, new_id);\n kept++;\n },\n { after: at, limit }\n );\n\n // Termination:\n // - got < batch: source honored limit but ran out (also covers\n // got === 0 — past-the-end on a paginating source).\n // - got > batch: source ignored the filter (CsvFile-style). It\n // streamed everything in one call; nothing left to ask for.\n // Otherwise (got === batch): more events may exist; bump and continue.\n if (got !== limit) break;\n at = id;\n }\n\n return {\n kept,\n migrated: migrated_count,\n dropped: {\n closed_streams: dropped_closed,\n snapshots: dropped_snaps,\n },\n };\n}\n\n/**\n * Loads a snapshot of the state from the store by folding events through the\n * state's patch reducers.\n *\n * First checks the cache for a checkpoint, then queries the store for events\n * committed after the cached position. On cache miss, replays from the store\n * (using snapshots if available to avoid full replay).\n *\n * @template TState The type of state\n * @template TEvents The type of events\n * @template TActions The type of actions\n * @param me The state machine definition.\n * @param stream The stream (instance) to load\n * @param callback (Optional) Callback to receive the loaded snapshot as it is built\n * @param asOf (Optional) Time-travel cursor; bypasses the cache.\n * @param actor (Optional) Passed through to the state's `view` delegate\n * when constructing the snapshot.event — semantics are the state's to\n * define (see {@link state}).\n * @returns The snapshot of the loaded state\n *\n * @example\n * const snapshot = await load(Counter, \"counter1\");\n */\nexport async function load<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n me: State<TState, TEvents, TActions>,\n target: LoadTarget,\n callback?: (snapshot: Snapshot<TState, TEvents>) => void,\n patch_fn: PatchFn = bare_patch\n): Promise<Snapshot<TState, TEvents>> {\n const { stream, actor, asOf } = target;\n const time_travel =\n !!asOf && Object.values(asOf).some((v) => v !== undefined);\n const cached = time_travel ? undefined : await cache().get<TState>(stream);\n const cache_hit = !!cached;\n let state = cached?.state ?? (me.init ? me.init() : ({} as TState));\n let patches = cached?.patches ?? 0;\n let snaps = cached?.snaps ?? 0;\n // replayed counts events processed by THIS load only (snap or patch);\n // distinct from `patches` (the snap-distance accumulator carried over\n // from the cache).\n let replayed = 0;\n let event: Committed<TEvents, keyof TEvents> | undefined;\n\n await store().query<TEvents>(\n (raw) => {\n event = me.view(raw, actor);\n if (event.name === SNAP_EVENT) {\n state = event.data as TState;\n snaps++;\n patches = 0;\n replayed++;\n } else if (me.patch[event.name]) {\n state = patch_fn(me, state, me.patch[event.name](event, state), event);\n patches++;\n replayed++;\n } else if (event.name !== TOMBSTONE_EVENT) {\n // Unknown event — not in this state's reducer map. Causes:\n // deleted/renamed event in a versioned schema, load() called with\n // the wrong state, or stream contamination. Skipping silently\n // would corrupt replay; warn so the operator can investigate.\n log().warn(\n `Skipping unknown event \"${String(event.name)}\" on stream \"${stream}\" (id=${event.id}) — no reducer in state \"${me.name}\"`\n );\n }\n callback?.({\n event,\n state,\n version: event.version,\n id: event.id,\n patches,\n snaps,\n cache_hit,\n replayed,\n });\n },\n {\n stream,\n stream_exact: true,\n // The snapshot resume floor is a current-state optimization: it only\n // holds when the load has no window of its own. `time_travel` already\n // captures that (any `asOf` bound set), so request `with_snaps` only for\n // a non-time-travel cold load — a bounded load full-scans real events\n // under its `asOf` filter. This is the single floor-eligibility decision\n // for the whole system; the stores apply the floor whenever asked and\n // never re-derive it (RFC 1274).\n //\n // The warm path resumes from `after`, and MUST also carry `with_snaps`\n // (#1345): `after` and `with_snaps` are independent store conditions —\n // `after` bounds the scan (id > cached.event_id), `with_snaps` keeps\n // `__snapshot__` rows in the result. A stale (lagging/cross-process)\n // cache checkpoint can sit below a newer `__snapshot__` boundary, and a\n // windowed close (`app.close`/`.autocloses({keep})`) may have pruned the\n // domain events between the checkpoint and that snapshot. Without\n // `with_snaps` the rebaselining snapshot is filtered out and the fold\n // silently applies the surviving tail on top of stale state (wrong\n // count, yet `version` still reports the true head — the concurrency\n // guard passes). With it, the snapshot in the after-window rebaselines\n // the fold; when no snapshot falls in the window it is a no-op.\n ...(cached\n ? { after: cached.event_id, with_snaps: true }\n : { ...(time_travel ? {} : { with_snaps: true }), ...asOf }),\n }\n );\n\n // Populate the cache when this load actually processed events. Without\n // this, read-heavy paths (UI loops calling load() many times between\n // commits) miss the cache forever — only action() would ever warm it.\n // No race-protection re-check needed: the cache is a state checkpoint\n // at (version, event_id), and any subsequent load queries past\n // event_id (with `with_snaps`, so a rebaselining snapshot above the\n // checkpoint is still folded even after a windowed close pruned the\n // events between them — #1345), picks up missed events, and replays — so\n // an \"older\" cache write from a concurrent slower load is self-correcting\n // on next access. Time-travel loads bypass cache entirely and skip this too.\n //\n // Skip the write when the replayed head is the tombstone (ACT-1188).\n // During the close guard window (tombstone committed, truncate pending)\n // a cold load replays real events + the tombstone, so `replayed > 0`.\n // Caching here would store a checkpoint at the tombstone's (version,\n // event_id) with no `event` on the entry — the next `action()` would\n // then get a warm hit where `snapshot.event` is undefined, its\n // cold-path tombstone check (`snapshot.event?.name === TOMBSTONE_EVENT`)\n // would go vacuously false, and a commit could land past the tombstone\n // that the eventual truncate deletes. Leaving the cache cold keeps that\n // check live on every subsequent load.\n const head_is_tombstone = event?.name === TOMBSTONE_EVENT;\n if (\n replayed > 0 &&\n !time_travel &&\n event &&\n !me.pii_aware &&\n !head_is_tombstone\n ) {\n // Fire-and-forget the checkpoint write, mirroring action() (ACT-1206):\n // the state is already correctly computed, so a transient failure in a\n // remote-backed Cache (e.g. a Redis blip) must not fail the read — that\n // would break plain reads, reaction bound_load dispatches, and the fold\n // engine's first-sight load. The cache is self-correcting: a subsequent\n // load queries past `event_id`, replays what it missed, and re-warms.\n await cache()\n .set(stream, {\n stream,\n state,\n version: event.version,\n event_id: event.id,\n patches,\n snaps,\n })\n .catch((err) => log().error(err));\n }\n\n return {\n event,\n state,\n version: event?.version ?? cached?.version ?? -1,\n // Head event id, captured atomically with `state`: the last replayed\n // event's id on a cache miss, or the cached checkpoint's event_id on a\n // warm hit with no new events. Consumers read this instead of a\n // separate cache lookup that could race a concurrent commit (ACT-1204).\n id: event?.id ?? cached?.event_id ?? -1,\n patches,\n snaps,\n cache_hit,\n replayed,\n };\n}\n\n/**\n * Executes an action and emits an event to be committed by the store.\n *\n * Validates the action, applies business invariants, emits events, and\n * commits them to the event store. When the action's\n * {@link ActionOptions} declare a retry budget, the orchestrator owns\n * the loop on {@link ConcurrencyError}: cache is invalidated, optional\n * `backoff` delay is applied, and the action re-runs from `load`. Any\n * other error rethrows immediately and does not consume the budget.\n *\n * Reactions skip optimistic concurrency (commit below passes\n * `undefined` as `expectedVersion` when `reactingTo` is set), so\n * `ConcurrencyError` cannot fire on the reaction-driven path — the\n * loop is naturally a no-op there.\n *\n * @template TState The type of state\n * @template TEvents The type of events\n * @template TActions The type of action_schemas\n * @template TKey The type of action to execute\n * @param me The state machine definition\n * @param action The action to execute\n * @param target The target (stream, actor, etc.)\n * @param payload The payload of the action\n * @param options Per-call dispatch options ({@link DoOptions}) —\n * `reactingTo` to thread correlation, `correlator` to override the\n * framework or orchestrator-level correlator for this call only.\n * @returns The snapshot of the committed event\n *\n * @example\n * const snapshot = await action(Counter, \"increment\", { stream: \"counter1\", actor }, { by: 1 });\n */\nexport async function action<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TKey extends keyof TActions,\n>(\n me: State<TState, TEvents, TActions>,\n action: TKey,\n target: Target,\n payload: Readonly<TActions[TKey]>,\n options?: DoOptions<TEvents>,\n patch_fn: PatchFn = bare_patch\n): Promise<Snapshot<TState, TEvents>[]> {\n const { stream, expectedVersion, actor } = target;\n if (!stream) throw new Error(\"Missing target stream\");\n const reactingTo = options?.reactingTo;\n const correlator = options?.correlator ?? default_correlator;\n\n const validated = validate(action as string, payload, me.actions[action]);\n\n const opts = me.options?.[action];\n const max_retries = opts?.maxRetries ?? 0;\n\n for (let attempt = 0; ; attempt++) {\n try {\n const snapshot = await load(\n me,\n { stream, actor: target.actor },\n undefined,\n patch_fn\n );\n if (snapshot.event?.name === TOMBSTONE_EVENT)\n throw new StreamClosedError(stream);\n // snapshot.version is the head version even on a warm cache hit,\n // where snapshot.event is undefined — using the event would\n // silently drop the optimistic guard for every cached stream.\n // A brand-new stream (-1) stays unguarded: creations append.\n const expected =\n expectedVersion ??\n (snapshot.version >= 0 ? snapshot.version : undefined);\n\n if (me.given) {\n const invariants = me.given[action] || [];\n invariants.forEach(({ valid, description }) => {\n if (!valid(snapshot.state, actor))\n throw new InvariantError(\n action,\n validated,\n target,\n snapshot,\n description\n );\n });\n }\n\n const result = me.on[action](validated, snapshot, target);\n if (!result) return [snapshot];\n\n // An empty array means no events were emitted\n if (Array.isArray(result) && result.length === 0) {\n return [snapshot];\n }\n\n const tuples = Array.isArray(result[0])\n ? (result as Emitted<TEvents>[]) // array of tuples\n : ([result] as Emitted<TEvents>[]); // single tuple\n\n const valid = tuples.map(([name, data]) => ({\n name,\n data: validate(name as string, data, me.events[name]),\n }));\n const emitted = valid.map((e) => me.message(e));\n\n const meta: EventMeta = {\n correlation:\n reactingTo?.meta.correlation ||\n correlator({\n action: action as string,\n state: me.name,\n stream,\n actor: target.actor,\n }),\n causation: {\n action: {\n name: action as string,\n ...target,\n // payload intentionally omitted from causation metadata —\n // callers correlate via the correlation id when they need it.\n },\n event: reactingTo\n ? {\n id: reactingTo.id,\n name: reactingTo.name as string,\n stream: reactingTo.stream,\n }\n : undefined,\n },\n };\n\n let committed: Committed<TEvents, keyof TEvents>[];\n try {\n committed = await store().commit(\n stream,\n emitted,\n meta,\n // Reactions skip optimistic concurrency: they always append against the\n // current head. Stream leasing already serializes concurrent reactions,\n // and forcing version checks here would turn ordinary catch-up into\n // spurious retries.\n reactingTo ? undefined : expected\n );\n } catch (error) {\n // Invalidate cache on concurrency errors — cached state is stale.\n //\n // Contained and NOT awaited, matching every other cache write on this\n // path (the load checkpoint, the action checkpoint, the gapped-commit\n // invalidate): a transient failure in a remote-backed Cache must not\n // fail the operation. Awaiting it unguarded here did two kinds of\n // damage (#1438). The caller got the cache's error instead of the\n // `ConcurrencyError`, so transports mapped a Redis blip to 500 rather\n // than 412. Worse, the substituted error failed the\n // `instanceof ConcurrencyError` test in the retry loop below, so a\n // conflict that would have resolved on reload+retry became a\n // permanent failure with the work lost.\n //\n // The invalidate is defensive anyway: the cache is self-correcting,\n // since a stale checkpoint is re-folded from `after: event_id`.\n if (error instanceof ConcurrencyError) {\n cache()\n .invalidate(stream)\n .catch((err) => log().error(err));\n }\n throw error;\n }\n\n let { state, patches } = snapshot;\n const snapshots = committed.map((row, i) => {\n // Actions originate from the caller — they already hold the\n // plaintext payload they sent. No view/gate round-trip is\n // useful; the reducer and the returned snapshot see the\n // pre-split event directly. pii_split (in `me.message`) above\n // is the only PII operation on the action path.\n const event = { ...row, data: valid[i].data };\n const p = me.patch[event.name](event, state);\n state = patch_fn(me, state, p, event);\n patches++;\n return {\n event,\n state,\n version: event.version,\n id: event.id,\n patches,\n snaps: snapshot.snaps,\n patch: p,\n cache_hit: snapshot.cache_hit,\n replayed: snapshot.replayed,\n };\n });\n\n // fire and forget snaps\n const last = snapshots.at(-1)!;\n // Guardless commits (reactions append at head by design) can land\n // past events this fold never saw. A gapped fold must not become\n // a snapshot event or a cache entry — both would lie at the head\n // position. Contiguity is cheap to prove: the first committed\n // version extends the loaded one.\n const contiguous = committed[0].version === snapshot.version + 1;\n const snapped = contiguous && me.snap?.(last);\n\n // Persist the snapshot before caching. Awaited on purpose: the\n // snapshot event occupies the next version slot, so a follow-up\n // action loading a pre-snap checkpoint from the cache would collide\n // with the framework's own bookkeeping. Caching the snap checkpoint\n // before the action returns keeps sequential callers from ever\n // seeing a conflict they didn't cause. Failures are still\n // swallowed inside snap() — the action never fails on it, and the\n // cache then keeps the pre-snap checkpoint, which stays correct.\n const snap_event = snapped ? await snap(last) : undefined;\n\n // #861: pii-aware states (any event declaring `sensitive(...)`\n // fields) never populate the snapshot cache — state evolves from\n // the actor-gated event view, so the cached state would vary by\n // caller. Pure states cache normally.\n // Fire-and-forget — log but don't fail the action on cache write errors\n // (e.g., transient network failures in a custom Cache adapter).\n if (!me.pii_aware) {\n if (contiguous)\n cache()\n .set<TState>(stream, {\n stream,\n state: last.state,\n version: snap_event?.version ?? last.event.version,\n event_id: snap_event?.id ?? last.event.id,\n patches: snap_event ? 0 : last.patches,\n snaps: snap_event ? last.snaps + 1 : last.snaps,\n })\n .catch((err) => log().error(err));\n // A gapped entry would sit at the head position with unfolded\n // events baked in — drop the checkpoint and let the next load\n // replay to truth instead.\n else\n cache()\n .invalidate(stream)\n .catch((err) => log().error(err));\n }\n\n return snapshots;\n } catch (error) {\n if (!(error instanceof ConcurrencyError)) throw error;\n // A caller-pinned expectedVersion is a fixed target: every retry\n // reloads and re-commits against the SAME pinned version, so the\n // conflict is guaranteed to recur — retrying only burns the budget\n // and sleeps out the backoff before surfacing the same terminal\n // error. Rethrow immediately (ACT-1208). The retry loop exists to\n // absorb races on framework-derived versions (a concurrent writer\n // advanced the head), where the reload picks up the new head\n // version and the next attempt can succeed.\n if (expectedVersion !== undefined) throw error;\n if (attempt >= max_retries) throw error;\n if (opts?.backoff) {\n const delay_ms = compute_backoff_delay(attempt, opts.backoff);\n if (delay_ms > 0) await sleep(delay_ms);\n }\n }\n }\n}\n","/**\n * @module backoff\n * @category Internal\n *\n * Per-reaction retry backoff delay computation. Pure function — keeps\n * `DrainController` and `reactions._finalize` testable in isolation.\n *\n * @internal\n */\n\nimport type { BackoffOptions } from \"../types/action.js\";\n\n// The `BackoffOptions` config schema + resolver live in `./config.ts` (the\n// single home for every builder-facing config bag). This module keeps only\n// the runtime delay math, which stays hot-path and dependency-free.\n\n/**\n * Compute the wall-clock delay (in ms) to wait before the next attempt on\n * a stream whose handler just failed.\n *\n * @param retry - The lease's `retry` counter at finalize time. `0` is the\n * first attempt that failed; `1` is after one retry; etc.\n * @param opts - Per-reaction backoff config. Returns `0` when undefined.\n * @returns Non-negative integer milliseconds. Always `0` when `opts` is\n * undefined or `baseMs <= 0`.\n */\nexport function compute_backoff_delay(\n retry: number,\n opts: BackoffOptions | undefined\n): number {\n if (!opts || opts.baseMs <= 0) return 0;\n const r = Math.max(0, retry);\n let delay: number;\n switch (opts.strategy) {\n case \"fixed\":\n delay = opts.baseMs;\n break;\n case \"linear\":\n delay = opts.baseMs * (r + 1);\n break;\n case \"exponential\":\n delay = opts.baseMs * 2 ** r;\n if (opts.maxMs !== undefined) delay = Math.min(delay, opts.maxMs);\n break;\n default: {\n // Unreachable once options pass `resolveBackoffConfig` at their\n // declaration site. Defensive so the pure function is total and can\n // never emit `NaN` from an unvalidated strategy — throw instead.\n const _never: never = opts.strategy;\n throw new Error(`unknown backoff strategy: ${String(_never)}`);\n }\n }\n if (opts.jitter) delay = delay * (0.5 + Math.random());\n return Math.max(0, Math.floor(delay));\n}\n","/**\n * @module tracing\n * @category Internal\n *\n * Centralized observability for the framework's internal pipelines.\n *\n * Trace decorators wrap a bare implementation with `logger.trace(...)` calls\n * at well-defined moments — entry points for {@link \"event-sourcing\"} (`load`,\n * `snap`, `action`) and exit points for the {@link \"drain\"} pipeline (`claim`,\n * `fetch`, `ack`, `block`, `subscribe`). `action` carries both an entry log\n * and a post-commit log to preserve the diagnostic value of the historical\n * mid-function trace points.\n *\n * Output styles:\n * - **Pretty mode** (`config().env !== \"production\"`) — event-sourcing logs\n * show only the colored target body (color carries the operation/phase),\n * drain logs keep a colored caption.\n * - **Plain mode** (production / log aggregators) — every log gets a textual\n * prefix; event-sourcing uses `caption: body`, drain uses `caption body`.\n *\n * The two factories — {@link build_es} and {@link build_drain} — let the\n * orchestrator choose bare or traced variants once at `.build()` time based\n * on the configured log level. Outside this module, no other source file\n * imports tracing primitives.\n *\n * @internal\n */\n\nimport { config } from \"../config.js\";\nimport type { AsOf, Correlator, Logger, Schemas } from \"../types/index.js\";\nimport { default_correlator } from \"./correlator.js\";\nimport type { DrainOps } from \"./drain.js\";\nimport * as drain from \"./drain.js\";\nimport type { EsOps, PatchFn } from \"./event-sourcing.js\";\nimport * as es from \"./event-sourcing.js\";\n\ntype AsyncFn = (...args: any[]) => Promise<any>;\n\nconst PRETTY = config().env !== \"production\";\n\n// 256-color codes for distinctive, theme-friendly hues\nconst C_BLUE = \"\\x1b[38;5;39m\"; // vivid sky blue (action)\nconst C_ORANGE = \"\\x1b[38;5;208m\"; // true orange (committed)\nconst C_GREEN = \"\\x1b[38;5;42m\"; // emerald (load)\nconst C_MAGENTA = \"\\x1b[38;5;165m\"; // bright magenta (snap)\nconst C_DRAIN = \"\\x1b[38;5;244m\"; // muted gray for all drain ops\n// load-trace cache marker shades — distinguishable from C_GREEN body color\nconst C_HIT = \"\\x1b[38;5;82m\"; // lime — fast path, blends visually\nconst C_MISS = \"\\x1b[38;5;220m\"; // amber — non-trivial work happened\nconst C_RESET = \"\\x1b[0m\";\n\n/**\n * Format an event-sourcing trace line. Pretty mode renders just the colored\n * body (the color is the cue for which op/phase fired); plain mode prepends\n * `caption: ` so log aggregators stay readable without ANSI.\n */\nconst es_caption = (caption: string, color: string, body: string): string =>\n PRETTY ? `${color}${body}${C_RESET}` : `${caption}: ${body}`;\n\n/**\n * Format a drain-pipeline caption. Drain logs keep a `>>` marker for easy\n * spotting in mixed log streams, plus a `caption` (past tense — every drain\n * trace fires on exit). All drain ops share one color (gray) so the pipeline\n * reads as a single channel; the caption disambiguates the phase. Lane\n * (ACT-1103) is appended in lilac, unwrapped, when set and non-default,\n * so the operator's eye lands on the lane name without parsing per-stream\n * detail. Per-stream `@at/retry` and fetched event lists are muted via\n * {@link dim} so the stream name itself reads loudest.\n */\nconst C_LANE = \"\\x1b[38;5;183m\"; // lilac — distinct from gray drain + drain ops\nconst C_DIM = \"\\x1b[38;5;240m\"; // dim gray — dimmer than C_DRAIN\nconst C_ERR = \"\\x1b[38;5;196m\"; // bright red — block marker\nconst C_STREAM = \"\\x1b[38;5;226m\"; // bright yellow — target stream names in drain/correlate traces\n\n/** Wrap with the muted color when pretty mode is on. Plain in production. */\nconst dim = (text: string): string =>\n PRETTY ? `${C_DIM}${text}${C_RESET}` : text;\n\n/** Wrap with a foreground color when pretty mode is on; bare in production. */\nconst hue = (color: string, text: string): string =>\n PRETTY ? `${color}${text}${C_RESET}` : text;\n\nconst drain_caption = (caption: string, lane?: string): string => {\n const show_lane = lane && lane !== \"default\";\n if (PRETTY) {\n const tag = `${C_DRAIN}>> ${caption}${C_RESET}`;\n return show_lane ? `${tag} ${C_LANE}${lane}${C_RESET}` : tag;\n }\n return show_lane ? `>> ${caption} ${lane}` : `>> ${caption}`;\n};\n\n/**\n * Format the cache hit/miss marker for the load trace. In pretty mode the\n * word is colored (lime for hit, amber for miss) and the surrounding\n * `C_GREEN` body color is restored after — embedded ANSI inside `es_caption`'s\n * outer wrap. Plain mode returns the bare word.\n */\nconst cache_marker = (hit: boolean): string => {\n const word = hit ? \"hit\" : \"miss\";\n if (!PRETTY) return word;\n return `${hit ? C_HIT : C_MISS}${word}${C_RESET}${C_GREEN}`;\n};\n\n/**\n * Format the load stats (`v=N replayed=N snaps=N patches=N`) for the load\n * trace. Muted gray in pretty mode so the cache marker reads as the most\n * important cue; plain mode returns the bare text.\n *\n * - `v` — stream head version (the version of the last event applied)\n * - `replayed` — events processed by THIS load past the cache point\n * - `snaps` — cumulative snapshots taken on this stream\n * - `patches` — events since the last snap (snap-policy accumulator)\n */\nconst stats_marker = (\n version: number,\n replayed: number,\n snaps: number,\n patches: number\n): string => {\n const text = `v=${version} replayed=${replayed} snaps=${snaps} patches=${patches}`;\n if (!PRETTY) return text;\n return `${C_DRAIN}${text}${C_RESET}${C_GREEN}`;\n};\n\n/**\n * Format the as-of marker for time-travel loads. Surfaces the active filter\n * fields (before id, created_before/after timestamps, limit) so an operator\n * can tell at a glance which slice was loaded. Empty `asOf` returns \"\" —\n * non-time-travel loads skip the marker entirely.\n */\nconst as_of_marker = (asOf: AsOf | undefined): string => {\n if (!asOf) return \"\";\n const parts: string[] = [];\n if (asOf.before !== undefined) parts.push(`before=${asOf.before}`);\n if (asOf.created_before !== undefined)\n parts.push(`created_before=${asOf.created_before.toISOString()}`);\n if (asOf.created_after !== undefined)\n parts.push(`created_after=${asOf.created_after.toISOString()}`);\n if (asOf.limit !== undefined) parts.push(`limit=${asOf.limit}`);\n return parts.length ? ` (as-of ${parts.join(\" \")})` : \" (as-of)\";\n};\n\n/**\n * Wraps an async function with optional `exit` and `entry` callbacks. Each\n * callback fires at the corresponding phase; both receive the call args, and\n * `exit` additionally receives the resolved result. Used to layer\n * `logger.trace` calls onto bare ops without changing their signatures.\n *\n * @internal\n */\nconst traced = <F extends AsyncFn>(\n inner: F,\n exit?: (result: Awaited<ReturnType<F>>, ...args: Parameters<F>) => void,\n entry?: (...args: Parameters<F>) => void\n): F =>\n (async (...args: Parameters<F>) => {\n entry?.(...args);\n const result = (await inner(...args)) as Awaited<ReturnType<F>>;\n exit?.(result, ...args);\n return result;\n }) as F;\n\n/**\n * Selects bare or traced event-sourcing handlers. Called once by the\n * orchestrator constructor.\n *\n * @internal\n */\nexport function build_es(\n logger: Logger,\n correlator: Correlator = default_correlator,\n patch_fn: PatchFn = es.bare_patch\n): EsOps {\n // Bake the orchestrator-level `correlator` into every `action()` call\n // so EsOps callers don't need to thread it. A per-call\n // `options.correlator` still wins — the orchestrator default fills in\n // only when the caller didn't supply one.\n //\n // ACT-1238: the per-event patch step is selected ONCE by the builder\n // (`act-builder.ts`) — bare vs validating — and passed in here already\n // bound, so this factory stays agnostic to `validateFoldedState`. It\n // just bakes the given `patch_fn` into the load/action closures, so\n // the projection-fold engine and close-cycle callers inherit the same\n // choice without threading anything through their own signatures. The\n // default (`bare_patch`) keeps direct callers on the pre-#1238 path.\n const bound_action: EsOps[\"action\"] = (\n me,\n action_name,\n target,\n payload,\n options\n ) =>\n es.action(\n me,\n action_name,\n target,\n payload,\n { correlator, ...options },\n patch_fn\n );\n const bound_load: EsOps[\"load\"] = (me, target, callback) =>\n es.load(me, target, callback, patch_fn);\n if (logger.level !== \"trace\") {\n return {\n snap: es.snap,\n load: bound_load,\n action: bound_action,\n tombstone: es.tombstone,\n };\n }\n return {\n snap: traced(es.snap, undefined, (snapshot) => {\n logger.trace(\n es_caption(\n \"snap\",\n C_MAGENTA,\n `${snapshot.event!.stream}@${snapshot.event!.version}`\n )\n );\n }),\n load: traced(bound_load, (result, _me, target) => {\n const stats = stats_marker(\n result.version,\n result.replayed,\n result.snaps,\n result.patches\n );\n logger.trace(\n es_caption(\n \"load\",\n C_GREEN,\n `${target.stream}${as_of_marker(target.asOf)} ${cache_marker(result.cache_hit)} ${stats}`\n )\n );\n }),\n action: traced(\n bound_action,\n (snapshots, _me, _action, target) => {\n const committed = snapshots.filter((s) => s.event);\n if (committed.length) {\n logger.trace(\n committed.map((s) => s.event!.data),\n es_caption(\n \"committed\",\n C_ORANGE,\n `${target.stream}.${committed.map((s) => s.event!.name).join(\", \")}`\n )\n );\n }\n },\n (_me, action, target, payload) => {\n logger.trace(\n payload as object,\n es_caption(\"action\", C_BLUE, `${target.stream}.${action}`)\n );\n }\n ),\n tombstone: traced(es.tombstone, (committed, stream) => {\n if (committed)\n logger.trace(\n es_caption(\"tombstoned\", C_ORANGE, `${stream}@${committed.version}`)\n );\n }),\n };\n}\n\n/**\n * Selects bare or traced drain-pipeline ops. Called once by the orchestrator\n * constructor.\n *\n * @internal\n */\nexport function build_drain<TEvents extends Schemas>(\n logger: Logger\n): DrainOps<TEvents> {\n // Cycle-level tracing happens in `DrainController.drain()` via\n // {@link trace_cycle} — claim/fetch/ack/block all flow into one log\n // line per cycle to give the operator a single atomic narrative.\n // `subscribe` stays decorated because it's driven from correlate-\n // cycle (not from run_drain_cycle) and doesn't fit the cycle shape.\n return {\n claim: drain.claim,\n fetch: drain.fetch,\n ack: drain.ack,\n block: drain.block,\n subscribe:\n logger.level !== \"trace\"\n ? drain.subscribe\n : traced(drain.subscribe, (result, streams) => {\n if (!result.subscribed) return;\n // Caption mirrors `drained`: lane in the caption when the\n // whole batch shares a single non-default lane. Mixed-lane\n // batches (rare — different correlated targets resolving\n // to different lanes in one scan) fall back to per-stream\n // `[lane]` tags, default-lane streams stay bare either way.\n const lanes = new Set(streams.map((s) => s.lane ?? \"default\"));\n const uniform_lane =\n lanes.size === 1 ? streams[0]?.lane : undefined;\n const data = streams\n .map(({ stream, lane }) =>\n uniform_lane || !lane || lane === \"default\"\n ? hue(C_STREAM, stream)\n : `${hue(C_STREAM, stream)}${dim(`[${lane}]`)}`\n )\n .join(\" \");\n logger.trace(\n `${drain_caption(\"correlated\", uniform_lane)} ${data}`\n );\n }),\n };\n}\n\n/**\n * Emit one cycle-level drain trace summarizing what happened in a\n * single `run_drain_cycle` pass. Per-stream rendering shape — outcome +\n * post-state anchored on the right:\n *\n * stream<-source [events] ✓ @<acked-at> — full success\n * stream<-source [events] ✗ @<failed-at>/<retry> (error) — total failure → blocked\n * stream<-source [events] ⚠ @<failed-at>/<retry> (error) — total failure → retrying\n * stream<-source [events] ✓ @<acked-at> ✗ @<failed-at>/<retry> (error) — partial then blocked\n * stream<-source [events] ✓ @<acked-at> ⚠ @<failed-at>/<retry> (error) — partial then retrying\n * stream<-source ⊘ @<at>/<retry> — deferred (backoff)\n *\n * Partial-success-then-failure is the dual-outcome case: events\n * 1..K succeeded (watermark advanced to K), event K+1 threw. The\n * trace renders both the lime `✓ @K` and the red/amber `✗`/`⚠ @K+1`\n * on the same line so an operator sees \"we made progress *and* then\n * something broke\" at a glance.\n *\n * Lane prefixes the caption in lilac when non-default. The outcome\n * marker and its adjacent post-state share the marker's color so the\n * eye reads \"outcome + where it landed\" as one unit. Per-stream\n * `[events]` and `(error)` stay dim — secondary context.\n *\n * @internal\n */\nexport function trace_cycle<TEvents extends Schemas>(\n logger: Logger,\n leased: ReadonlyArray<{\n readonly stream: string;\n readonly at: number;\n readonly retry: number;\n readonly lane?: string;\n }>,\n fetched: ReadonlyArray<{\n readonly stream: string;\n readonly source?: string;\n readonly events: ReadonlyArray<{\n readonly id: number;\n readonly name: keyof TEvents;\n }>;\n }>,\n handled: ReadonlyArray<{\n readonly lease: { readonly stream: string };\n readonly error?: string;\n readonly block?: boolean;\n readonly failed_at?: number;\n }>,\n acked: ReadonlyArray<{ readonly stream: string; readonly at: number }>,\n blocked: ReadonlyArray<{ readonly stream: string; readonly error: string }>\n): void {\n if (logger.level !== \"trace\" || !leased.length) return;\n const lane = leased[0]?.lane;\n const fetch_by_stream = new Map(fetched.map((f) => [f.stream, f]));\n const acked_by_stream = new Map(acked.map((a) => [a.stream, a.at]));\n const blocked_by_stream = new Map(blocked.map((b) => [b.stream, b.error]));\n // Handled-with-error stays a single index now: `block` discriminates\n // the marker (✗ vs ⚠); the failure exists independently of whether\n // ack happened.\n const failed_by_stream = new Map(\n handled.filter((h) => h.error).map((h) => [h.lease.stream, h] as const)\n );\n const detail = leased\n .map(({ stream, at, retry }) => {\n const f = fetch_by_stream.get(stream);\n // Target stream in yellow so the operator's eye lands on \"which\n // stream did this happen on?\" first; source (the events' origin)\n // stays dim — secondary info.\n const key = f?.source\n ? `${hue(C_STREAM, stream)}${dim(`<-${f.source}`)}`\n : hue(C_STREAM, stream);\n const events = f?.events.length\n ? ` ${dim(\n `[${f.events.map(({ id, name }) => `#${id} ${String(name)}`).join(\", \")}]`\n )}`\n : \"\";\n // Build ack + fail segments independently — both can fire for\n // the same stream in the partial-success-then-failure case.\n const acked_at = acked_by_stream.get(stream);\n const ack_part =\n acked_at !== undefined\n ? hue(C_HIT, `✓ @${acked_at}`) // ✓ + new at in lime\n : \"\";\n const failure = failed_by_stream.get(stream);\n let fail_part = \"\";\n if (failure) {\n // Failed event id when known (per-event path), else falls back\n // to lease.at — the post-fetch watermark — for batch-mode\n // total failures where no single event is \"the one.\"\n const failed_at = failure.failed_at ?? at;\n const blocked_error = blocked_by_stream.get(stream);\n if (blocked_error !== undefined) {\n fail_part = `${hue(C_ERR, `✗ @${failed_at}/${retry}`)} ${dim(`(${blocked_error})`)}`;\n } else {\n fail_part = `${hue(C_MISS, `⚠ @${failed_at}/${retry}`)} ${dim(`(${failure.error})`)}`;\n }\n }\n let tail: string;\n if (ack_part && fail_part) tail = ` ${ack_part} ${fail_part}`;\n else if (ack_part) tail = ` ${ack_part}`;\n else if (fail_part) tail = ` ${fail_part}`;\n else tail = ` ${dim(`⊘ @${at}/${retry}`)}`; // nothing happened\n return `${key}${events}${tail}`;\n })\n .join(\", \");\n logger.trace(`${drain_caption(\"drained\", lane)} ${detail}`);\n}\n","/**\n * @module projection-fold\n * @category Internal\n *\n * Fold engine behind `projection(name).of(state)` — maintains per-stream\n * folded states in a bounded in-memory cache and flushes one row per dirty\n * stream per round, so write amplification tracks the distinct-key count\n * instead of the event count.\n *\n * The flush payload deliberately has no type of its own: a state\n * projection flushes the cache layer outward — the rows ARE the\n * streams' {@link CacheEntry} values.\n *\n * Correctness discipline:\n * - The engine runs as the projection's batch handler, so the watermark\n * acks only after a fully-flushed batch — fold work is never\n * acknowledged before it is durable.\n * - On first sight of a stream the engine loads its head state through\n * the same `load()` the command path uses (cache, snapshots and all).\n * The loaded snapshot carries its own head position (`version` and the\n * global event `id`), captured atomically with `state`, so the engine\n * never pairs a stale state with a newer head id read separately from\n * the cache (ACT-1204). Fetched events at or below the loaded id are\n * skipped, later ones fold through the state's own patch reducers.\n * - Eviction under `maxCachedStates` pressure flushes the evictee first\n * (flush-before-evict) — eviction never loses folded work.\n */\nimport type {\n BatchHandler,\n CacheEntry,\n Schema,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport type { FoldConfig } from \"./config.js\";\nimport { bare_patch, load, type PatchFn } from \"./event-sourcing.js\";\nimport { pii_strip } from \"./sensitive.js\";\n\n// The fold config schema, defaults, and resolver live in `./config.js` (the\n// single home for builder-facing config bags). This module keeps the fold\n// engine that consumes the resolved config.\n\n/**\n * A stream's in-flight fold: a mutable {@link CacheEntry} plus the\n * engine's `dirty` flag. Mutable because the hot loop updates one\n * object per stream rather than allocating per event; the required\n * frontier fields are what keep a warm-cache load from ever\n * re-applying history. Stripping `dirty` at the flush boundary yields\n * the entry — the flush payload IS the cache entry.\n */\ntype Fold<TState extends Schema> = {\n -readonly [K in keyof CacheEntry<TState>]: CacheEntry<TState>[K];\n} & { dirty: boolean };\n\n/**\n * Build the batch handler that folds a state's events into per-stream rows.\n * The returned closure is long-lived (one per built projection): its cache\n * survives across drain cycles, so warm streams fold without I/O.\n */\nexport function make_fold_handler<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n me: State<TState, TEvents, TActions>,\n flush: (rows: ReadonlyArray<CacheEntry<TState>>) => Promise<void>,\n config: FoldConfig,\n patch_fn: PatchFn = bare_patch,\n sensitive_fields: (event_name: string) => readonly string[]\n): BatchHandler<TEvents> {\n // First-sight head loads must apply the SAME PII treatment as the warm\n // path (which folds `pii_strip`ped events handed in by the batch handler):\n // sensitive keys removed entirely, not gated to `[REDACTED]`. `load()`\n // folds over `me.view`, so compose the view with `pii_strip` for sensitive\n // events — otherwise an actorless head load would gate to `[REDACTED]` and\n // the projected row would differ from the warm path by cache warmth (#1320).\n // For a non-PII projection every lookup is empty, so `load_me === me`\n // behaviorally.\n const load_me: State<TState, TEvents, TActions> = {\n ...me,\n view: (raw, actor) => {\n const viewed = me.view(raw, actor);\n const fields = sensitive_fields(viewed.name as string);\n return fields.length\n ? (pii_strip(viewed as never, fields) as typeof viewed)\n : viewed;\n },\n };\n // Insertion-ordered Map as LRU: first key is the oldest. A promote is\n // delete + re-insert. Not the shared LruMap — eviction here must await\n // a flush, and a sync auto-evicting set() would drop folded work.\n const cache = new Map<string, Fold<TState>>();\n\n const row = ({ dirty: _, ...row }: Fold<TState>): CacheEntry<TState> => row;\n\n const flush_dirty = async () => {\n const rows: CacheEntry<TState>[] = [];\n const flushed: Fold<TState>[] = [];\n for (const f of cache.values())\n if (f.dirty) {\n rows.push(row(f));\n flushed.push(f);\n }\n if (rows.length === 0) return;\n await flush(rows);\n for (const f of flushed) f.dirty = false;\n };\n\n return async (events) => {\n let folded_since_flush = 0;\n for (const event of events) {\n const stream = event.stream;\n let fold = cache.get(stream);\n if (fold) {\n // promote to most-recent\n cache.delete(stream);\n cache.set(stream, fold);\n } else {\n if (cache.size >= config.maxCachedStates) {\n // flush-before-evict: the oldest entry leaves only after its\n // folded work is durable.\n const oldest = cache.keys().next().value as string;\n const evictee = cache.get(oldest) as Fold<TState>;\n if (evictee.dirty) await flush([row(evictee)]);\n cache.delete(oldest);\n }\n // First sight of this stream: load its head state through the\n // regular load path (cache, snapshots). The loaded state and its\n // head position (`version`, global `id`, `patches`, `snaps`) are\n // captured atomically inside `load()` — even on a warm cache hit\n // where `snapshot.event` is undefined. Reading the head id back\n // from the cache separately (ACT-1204) opened a TOCTOU window: a\n // concurrent `action()` committing between the two awaits pairs\n // this OLDER state with a NEWER event_id, and the\n // `event.id > fold.event_id` guard below then permanently skips\n // the intervening events. Dirty from the start: the row must be\n // written at least once.\n const snapshot = await load(load_me, { stream }, undefined, patch_fn);\n fold = {\n stream,\n state: snapshot.state,\n version: snapshot.version,\n event_id: snapshot.id,\n patches: snapshot.patches,\n snaps: snapshot.snaps,\n dirty: true,\n };\n cache.set(stream, fold);\n }\n if (event.id > fold.event_id) {\n const reducer = me.patch[event.name as keyof TEvents];\n fold.state = patch_fn(\n me,\n fold.state,\n reducer(event as never, fold.state),\n event as never\n );\n fold.version = event.version;\n fold.event_id = event.id;\n fold.patches++;\n fold.dirty = true;\n } else {\n // Already folded (head load or redelivery) — mark dirty anyway\n // so replays repopulate the read table: this is what keeps a\n // rebuild at one upsert per stream instead of zero.\n fold.dirty = true;\n }\n if (++folded_since_flush >= config.flushEvery) {\n await flush_dirty();\n folded_since_flush = 0;\n }\n }\n // Flush before returning: the drain acks this batch's watermark only\n // after the handler resolves, so rows are durable before the ack.\n await flush_dirty();\n };\n}\n","/**\n * @module reactions\n * @category Internal\n *\n * Reaction dispatch — what runs inside the drain pipeline once `run_drain_cycle`\n * has fetched events for a leased stream. Two shapes:\n *\n * - per-event `handle`: walks payloads sequentially, builds a scoped `IAct`\n * that auto-injects `reactingTo` so handlers don't have to thread it\n * through manually\n * - bulk `handle_batch`: hands every event for a static-target projection to\n * a single batch callback, enabling one-transaction replays\n *\n * Both share `_finalize`, which collapses the retry-vs-block decision and\n * the \"report error only when nothing was handled\" rule.\n *\n * @internal\n */\n\nimport {\n type Actor,\n type BatchHandler,\n type Committed,\n type DoOptions,\n type IAct,\n type Lease,\n type Logger,\n NonRetryableError,\n type ReactionOptions,\n type ReactionPayload,\n type Schemas,\n type Target,\n} from \"../types/index.js\";\nimport { compute_backoff_delay } from \"./backoff.js\";\nimport { CloseSignal } from \"./close-signal.js\";\nimport { resolve_defer_at } from \"./defer-config.js\";\nimport { DeferSignal } from \"./defer-signal.js\";\nimport type { Handle, HandleBatch, HandleResult } from \"./drain-cycle.js\";\n\n/**\n * Dependencies a reaction handler needs from the orchestrator: the logger\n * for retry/error breadcrumbs, plus the bound `IAct` methods that the scoped\n * proxy hands to user reaction code.\n *\n * @internal\n */\nexport type ReactionDeps<\n TEvents extends Schemas,\n TActions extends Schemas,\n TActor extends Actor = Actor,\n> = {\n readonly logger: Logger;\n readonly bound_do: IAct<TEvents, TActions, TActor>[\"do\"];\n readonly bound_load: IAct<TEvents, TActions, TActor>[\"load\"];\n readonly bound_query: IAct<TEvents, TActions, TActor>[\"query\"];\n readonly bound_query_array: IAct<TEvents, TActions, TActor>[\"query_array\"];\n readonly bound_forget: IAct<TEvents, TActions, TActor>[\"forget\"];\n};\n\n/**\n * Shared finalization: log the error and decide retry vs. block. The\n * error string is *always* surfaced on the failure path — drain-cycle\n * uses `handled > 0` (not `error` presence) to decide whether to ack\n * the partial progress, so the message can travel for trace + blocked\n * record without affecting the ack/skip choice.\n */\nfunction finalize(\n lease: Lease,\n handled: number,\n at: number,\n error: Error | undefined,\n options: ReactionOptions,\n logger: Logger,\n failed_at?: number\n): HandleResult {\n if (!error) return { lease, handled, acked_at: at };\n logger.error(error);\n // A `NonRetryableError` from the handler short-circuits the retry\n // budget — block on first attempt when the operator has opted in via\n // `blockOnError`. When `blockOnError` is false, the operator has\n // explicitly chosen \"retry forever,\" so we don't override that.\n const non_retryable = error instanceof NonRetryableError;\n const block =\n options.blockOnError &&\n (non_retryable || lease.retry >= options.maxRetries);\n if (block)\n logger.error(\n non_retryable\n ? `Blocking ${lease.stream} on non-retryable error.`\n : `Blocking ${lease.stream} after ${lease.retry} retries.`\n );\n // Backoff applies only on retry paths — successful handles and terminal\n // blocks never defer. `lease.retry` here is the just-failed attempt's\n // counter, so the delay paces the *next* attempt.\n const next_attempt_at =\n !block && options.backoff\n ? Date.now() + compute_backoff_delay(lease.retry, options.backoff)\n : undefined;\n return {\n lease,\n handled,\n acked_at: at,\n error: error.message,\n block,\n next_attempt_at,\n failed_at,\n };\n}\n\n/**\n * Builds the per-event reaction dispatcher passed to `run_drain_cycle`.\n *\n * The scoped `IAct` proxy auto-injects the triggering event as `reactingTo`\n * when handlers call `do()` without it (#587), keeping the correlation\n * chain by default. The non-do methods are reused across all dispatches —\n * only `do` rebinds per payload because it captures the triggering event.\n *\n * @internal\n */\nexport function build_handle<\n TEvents extends Schemas,\n TActions extends Schemas,\n TActor extends Actor = Actor,\n>(deps: ReactionDeps<TEvents, TActions, TActor>): Handle<TEvents> {\n const {\n logger,\n bound_do,\n bound_load,\n bound_query,\n bound_query_array,\n bound_forget,\n } = deps;\n return async (lease, payloads) => {\n if (payloads.length === 0) return { lease, handled: 0, acked_at: lease.at };\n\n const stream = lease.stream;\n // One event fans out to one payload per matching reaction, and the\n // watermark may only advance past an event once EVERY reaction on it\n // has handled it — acking mid-group would silently drop the remaining\n // reactions on redelivery (#1179). Track the last payload index per\n // event id (payloads arrive in event order) so `at` advances exactly\n // when a group completes; `handled` counts completed events, not\n // payloads, so a mid-group failure with no completed events is a\n // no-progress result (no ack, retry counter advances toward\n // `blockOnError` instead of resetting on every partial pass).\n const last_index_of = new Map<number, number>();\n for (let i = 0; i < payloads.length; i++)\n last_index_of.set(payloads[i].event.id, i);\n let at = lease.at;\n let handled = 0;\n\n if (lease.retry > 0)\n logger.warn(\n `Retrying ${stream}@${payloads.at(0)!.event.id} (${lease.retry}).`\n );\n\n const scoped_app: IAct<TEvents, TActions, TActor> = {\n do: bound_do,\n load: bound_load,\n query: bound_query,\n query_array: bound_query_array,\n forget: bound_forget,\n };\n\n for (let i = 0; i < payloads.length; i++) {\n const payload = payloads[i];\n const { event, handler } = payload;\n scoped_app.do = <TKey extends keyof TActions & string>(\n action: TKey,\n target: Target<TActor>,\n action_payload: Readonly<TActions[TKey]>,\n options?: DoOptions<TEvents>\n ) =>\n bound_do(action, target, action_payload, {\n ...options,\n reactingTo:\n options?.reactingTo ?? (event as Committed<Schemas, string>),\n });\n try {\n await handler(event, stream, scoped_app);\n if (last_index_of.get(event.id) === i) {\n at = event.id;\n handled++;\n }\n } catch (error) {\n // A defer is not a failure: hold the triggering events pending\n // (exclude from ack via `defer`), don't bump `retry`, and re-visit\n // the stream at the carried due-time (#1090). `acked_at` is unused on\n // the defer path — drain never acks a deferred result.\n if (error instanceof DeferSignal)\n return {\n lease,\n handled,\n acked_at: at,\n defer: resolve_defer_at<TEvents>(error.when, event),\n };\n // A close request advances past the triggering event (so the\n // requesting reaction isn't counted as in-flight by the close-cycle\n // guard) and hands the target to the orchestrator's on_close (#1090).\n if (error instanceof CloseSignal)\n return {\n lease,\n handled: handled + 1,\n // Advance to the live head the handler evaluated against (when\n // provided) so the close-cycle guard sees this reaction caught up.\n acked_at: error.at ?? event.id,\n // Close the signalled stream (the autoclose reaction's aggregate,\n // which differs from its synthetic lease stream); a self-closing\n // user reaction omits it and closes its own lease stream. A\n // carried `before` makes it a windowed close (prune, not retire).\n close: {\n stream: error.stream ?? stream,\n archive: error.archive,\n before: error.before,\n },\n };\n return finalize(\n lease,\n handled,\n at,\n error as Error,\n payload.options,\n logger,\n event.id\n );\n }\n }\n return finalize(lease, handled, at, undefined, payloads[0].options, logger);\n };\n}\n\n/**\n * Builds the bulk reaction dispatcher passed to `run_drain_cycle`. All events\n * for a static-target projection are handed to a single callback so the\n * projection can do one transaction per drain (catch-up replays especially).\n *\n * @internal\n */\nexport function build_handle_batch<TEvents extends Schemas>(\n logger: Logger\n): HandleBatch<TEvents> {\n return async (\n lease: Lease,\n payloads: ReactionPayload<TEvents>[],\n batchHandler: BatchHandler<TEvents>\n ) => {\n const stream = lease.stream;\n const events = payloads.map(\n (p) => p.event as Committed<TEvents, keyof TEvents & string>\n );\n const options = payloads[0].options;\n\n if (lease.retry > 0)\n logger.warn(`Retrying batch ${stream}@${events[0].id} (${lease.retry}).`);\n\n try {\n await batchHandler(events, stream);\n return finalize(\n lease,\n events.length,\n events.at(-1)!.id,\n undefined,\n options,\n logger\n );\n } catch (error) {\n return finalize(lease, 0, lease.at, error as Error, options, logger);\n }\n };\n}\n","/**\n * @module settle\n * @category Internal\n *\n * Debounced correlate→drain loop. Sits one level above both correlation\n * and drain: schedule() coalesces rapid callers into a single cycle, then\n * runs correlate+drain in a loop until a pass produces no progress.\n *\n * Owns the debounce timer and the reentrancy flag. Everything else is\n * supplied via the `SettleDeps` callbacks so this module stays free of\n * orchestrator state.\n *\n * @internal\n */\n\nimport type {\n Drain,\n DrainOptions,\n Query,\n Schemas,\n SettleOptions,\n} from \"../types/index.js\";\nimport type { CircuitBreaker } from \"./circuit-breaker.js\";\n\n/**\n * Callbacks the settle loop needs from the orchestrator. Modeled as an\n * input bag so this file doesn't import `Act` (avoids a cycle) and stays\n * independently testable.\n *\n * @internal\n */\nexport type SettleDeps<TEvents extends Schemas> = {\n readonly init: () => Promise<void>;\n readonly checkpoint: () => number;\n readonly correlate: (\n query: Query\n ) => Promise<{ subscribed: number; last_id: number }>;\n readonly drain: (options: DrainOptions) => Promise<Drain<TEvents>>;\n readonly on_settled: (drain: Drain<TEvents>) => void;\n /**\n * Shared orchestrator circuit breaker (ACT-984). The settle loop's\n * `correlate` (subscribe + query) is a store consumer too: a successful\n * pass records `passed()`, a failed one `failed(now, err)` — feeding the\n * same breaker that paces the drain loop, which also surfaces the failure\n * to the `error` lifecycle event.\n */\n readonly breaker: CircuitBreaker;\n /**\n * Whether `correlate` actually probes the store (the app has dynamic\n * resolvers). When false, correlate is a pure no-op early-return that\n * touches no store — so a settle pass has NO store-health signal and must\n * NOT record a breaker `passed()`. Recording a fictitious success there\n * would re-close an OPEN breaker mid-outage on a static-reaction app and\n * let the following drain hammer the down store (#1329). The drain loop's\n * own `passed()`/`failed()` on its real claim keeps the breaker accurate.\n */\n readonly correlate_probes_store: boolean;\n};\n\n/**\n * Drives the debounced correlate→drain catch-up cycle. One instance per\n * Act orchestrator.\n *\n * @internal\n */\nexport class SettleLoop<TEvents extends Schemas> {\n private _timer: ReturnType<typeof setTimeout> | undefined = undefined;\n private _running = false;\n /**\n * Set when a `schedule()` timer fires while a cycle is still running\n * (ACT-1205). The in-flight cycle's `finally` re-arms one more pass so\n * the wake-up isn't dropped — a commit landing during the final\n * no-progress drain pass would otherwise leave armed controllers with\n * nothing to re-drain on an instance with no lane `cycleMs` and no\n * polling. Carries the options of the dropped call so the re-armed\n * pass honors its `debounceMs`/`maxPasses`/drain overrides.\n */\n private _pending: SettleOptions | undefined = undefined;\n private readonly _deps: SettleDeps<TEvents>;\n /** Debounce window applied when the caller doesn't override via `SettleOptions.debounceMs`. */\n private readonly _default_debounce_ms: number;\n\n constructor(deps: SettleDeps<TEvents>, default_debounce_ms: number) {\n this._deps = deps;\n this._default_debounce_ms = default_debounce_ms;\n }\n\n /**\n * Schedule a settle pass. Multiple calls inside the debounce window\n * coalesce into one cycle. The cycle runs correlate→drain in a loop\n * until no progress is made (no new subscriptions, no acks, no blocks)\n * or `maxPasses` is reached, then emits the `\"settled\"` lifecycle event\n * via {@link SettleDeps.on_settled}.\n */\n schedule(options: SettleOptions = {}): void {\n const {\n debounceMs = this._default_debounce_ms,\n correlate: correlate_query = { after: -1, limit: 100 },\n maxPasses = Infinity,\n ...drain_options\n } = options;\n\n if (this._timer) clearTimeout(this._timer);\n this._timer = setTimeout(() => {\n this._timer = undefined;\n // A cycle is already running. Record this wake-up as pending rather\n // than dropping it (ACT-1205) — the running cycle's `finally`\n // re-schedules it so armed controllers always get one more drain.\n if (this._running) {\n this._pending = options;\n return;\n }\n this._running = true;\n\n (async () => {\n await this._deps.init();\n // Accumulated across every pass, so `settled` reports what the\n // SETTLE did rather than what its last pass did. The loop only\n // exits on a pass that made no progress, so emitting that pass\n // alone meant the payload was always empty — while the guide tells\n // operators to sum `drain.fetched` for throughput (#1383).\n let settled_drain: Drain<TEvents> | undefined;\n // Loop correlate→drain until a pass produces no work — this fully\n // catches up paginated streams (e.g. after `reset()` on a long\n // projection) without forcing callers to roll their own loop.\n // `maxPasses` caps runtime in pathological cases.\n for (let i = 0; i < maxPasses; i++) {\n const after_before = this._deps.checkpoint();\n const { subscribed, last_id } = await this._deps.correlate({\n ...correlate_query,\n after: after_before,\n });\n // correlate (subscribe + query) succeeded — the store responded.\n // But only record the success when correlate actually PROBED the\n // store: a static-reaction app's correlate is a no-op early-return\n // that touches nothing, so a `passed()` here would fictitiously\n // re-close an OPEN breaker mid-outage and let the drain below\n // hammer the down store (#1329). drain's own passed()/failed() on\n // its real claim keeps the breaker accurate for those apps.\n if (this._deps.correlate_probes_store) this._deps.breaker.passed();\n const drain = await this._deps.drain(drain_options);\n settled_drain = settled_drain\n ? {\n fetched: [...settled_drain.fetched, ...drain.fetched],\n leased: [...settled_drain.leased, ...drain.leased],\n acked: [...settled_drain.acked, ...drain.acked],\n blocked: [...settled_drain.blocked, ...drain.blocked],\n }\n : drain;\n // `last_id > after_before` counts correlate consuming events as\n // progress even when nothing subscribed or drained this pass — a\n // bounded correlate window (`limit`) full of inert events would\n // otherwise break the loop before a reactive event just past the\n // window is ever scanned. Terminates: ids are monotonic and\n // finite, so once no events remain `last_id === after_before`.\n const made_progress =\n subscribed > 0 ||\n drain.acked.length > 0 ||\n drain.blocked.length > 0 ||\n last_id > after_before;\n if (!made_progress) break;\n }\n // The `.catch` below treats anything it sees as a store failure,\n // because everything else in this block is one. An uncontained\n // listener throw was therefore recorded via `breaker.failed()` —\n // surfacing a spurious `error` event on every settle, and, at\n // `failureThreshold: 1`, opening the breaker so `drain` returned\n // EMPTY_DRAIN for the whole cooldown. Each half-open recovery\n // re-tripped it, so a broken metrics bridge stalled the reaction\n // pipeline indefinitely (#1436). Containment now lives in\n // `Act.emit`, which guards each listener individually (#1437), so\n // no throw escapes `on_settled` to reach that catch.\n if (settled_drain) this._deps.on_settled(settled_drain);\n })()\n .catch((err) => {\n // correlate / init failed (a store op). Record on the shared\n // breaker, which logs it and surfaces the `error` event; the\n // drain loop reads the same breaker to pace itself.\n this._deps.breaker.failed(Date.now(), err);\n })\n .finally(() => {\n this._running = false;\n // A wake-up arrived mid-cycle. Re-arm one more pass with its\n // options so the requested drain actually happens (ACT-1205).\n const pending = this._pending;\n if (pending !== undefined) {\n this._pending = undefined;\n this.schedule(pending);\n }\n });\n }, debounceMs);\n }\n\n /** Cancel any pending or active settle cycle. Idempotent. */\n stop(): void {\n // Drop a mid-cycle wake-up too — a stopped loop must not re-arm from\n // the running cycle's `finally` (ACT-1205).\n this._pending = undefined;\n if (this._timer) {\n clearTimeout(this._timer);\n this._timer = undefined;\n }\n }\n}\n","/**\n * @module act-builder\n * @category Builders\n *\n * Fluent builder for composing event-sourced applications.\n */\nimport { Act, type ActOptions } from \"../act.js\";\nimport {\n bare_patch,\n current_version_of,\n deprecated_event_names,\n type EventGate,\n IDENTITY_GATE,\n make_fold_handler,\n make_gate,\n merge_event_register,\n merge_projection,\n type PatchFn,\n pii_fields,\n pii_split,\n pii_strip,\n reaction_on,\n register_lane,\n register_state,\n resolveActConfig,\n resolveAutocloseConfig,\n resolveLaneConfig,\n synthesize_autoclose_reactions,\n validating_patch,\n} from \"../internal/index.js\";\nimport { DEFAULT_LANE, log } from \"../ports.js\";\nimport type {\n Actor,\n BatchHandler,\n LaneConfig,\n Reaction,\n Registry,\n Schema,\n SchemaRegister,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport type { BuilderBase } from \"./builder-base.js\";\nimport type { Projection } from \"./projection-builder.js\";\nimport type { Slice } from \"./slice-builder.js\";\n\n/**\n * Registers a projection's batch handler against its target stream, throwing\n * if a different handler is already registered for the same target. Two\n * projections silently overwriting each other's batch handlers used to be a\n * latent footgun.\n *\n * This half covers batch x batch only. A fold projection (`.of(...)`) has a\n * target but no batch handler, so it early-returns here — the fold side of\n * the guard lives at the `fold_specs.push` site in `build()`, which sees a\n * fully-populated `batch_handlers` and so catches both orders (#1440).\n */\nfunction register_batch_handler(\n proj: Projection<any>,\n batch_handlers: Map<string, BatchHandler<any>>\n): void {\n if (!proj.batchHandler || !proj.target) return;\n const existing = batch_handlers.get(proj.target);\n if (existing && existing !== proj.batchHandler) {\n throw new Error(\n `Duplicate projection target \"${proj.target}\" — a target is served by one batch handler or one state projection, never both`\n );\n }\n batch_handlers.set(proj.target, proj.batchHandler);\n}\n\n/**\n * Runtime backstop for slice-declared lane references — rejects\n * static `.to({lane})` entries that aren't in the declared set.\n * Inline reactions are caught at compile time; this only fires for\n * slices built against older type definitions.\n */\nfunction validate_lane_references(\n registry: Registry<any, any, any>,\n lanes: ReadonlyArray<LaneConfig>\n): void {\n const declared = new Set<string>([DEFAULT_LANE, ...lanes.map((l) => l.name)]);\n for (const [event_name, def] of Object.entries(registry.events)) {\n const entry = def as { reactions: Map<string, Reaction<any, any>> };\n for (const [handlerName, reaction] of entry.reactions) {\n const resolver = reaction.resolver;\n if (typeof resolver === \"function\") continue;\n const lane = (resolver as { lane?: string }).lane;\n if (lane && !declared.has(lane)) {\n throw new Error(\n `Reaction \"${handlerName}\" on \"${event_name}\" targets undeclared lane \"${lane}\". ` +\n `Declared lanes: ${[...declared].map((l) => `\"${l}\"`).join(\", \")}. ` +\n `Add \\`.withLane({ name: \"${lane}\", ... })\\` to act() or correct the .to() declaration.`\n );\n }\n }\n }\n}\n\n/**\n * Fluent builder interface for composing event-sourced applications.\n *\n * Provides a chainable API for:\n * - Registering states via `.withState()`\n * - Registering slices via `.withSlice()`\n * - Registering projections via `.withProjection()`\n * - Locking a custom actor type via `.withActor<TActor>()`\n * - Declaring drain lanes via `.withLane({name, ...})` (ACT-1103)\n * - Defining event reactions via `.on()` → `.do()` → `.to()`\n * - Building the orchestrator via `.build()`\n *\n * @template TSchemaReg - Schema register for states (maps action names to state schemas)\n * @template TEvents - Event schemas (maps event names to event data schemas)\n * @template TActions - Action schemas (maps action names to action payload schemas)\n * @template TStateMap - Map of state names to state schemas\n * @template TActor - Actor type extending base Actor\n * @template TLanes - Union of declared lane names (ACT-1103). Narrowed by\n * `.withLane({name})` calls so `.to({lane})` and `ActOptions.onlyLanes`\n * reject typos at compile time. Starts at `\"default\"`.\n *\n * @see {@link act} for usage examples\n * @see {@link Act} for the built orchestrator API\n */\nexport interface ActBuilder<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n TLanes extends string = typeof DEFAULT_LANE,\n> extends BuilderBase<\n ActBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor, TLanes>,\n TEvents,\n TActions,\n TActor,\n TLanes\n > {\n /**\n * Registers a state definition with the builder.\n *\n * State names, action names, and event names must be unique across the\n * application (partial states with the same name are merged automatically).\n *\n * @throws {Error} If duplicate action or event names are detected\n */\n withState: <\n TNewState extends Schema,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n TNewName extends string = string,\n >(\n state: State<TNewState, TNewEvents, TNewActions, TNewName>\n ) => ActBuilder<\n TSchemaReg & { [K in keyof TNewActions]: TNewState },\n TEvents & TNewEvents,\n TActions & TNewActions,\n TStateMap & { [K in TNewName]: TNewState },\n TActor,\n TLanes\n >;\n /**\n * Registers a slice with the builder.\n *\n * Merges all the slice's states and reactions into the application.\n * State names, action names, and event names must be unique across the\n * application (partial states with the same name are merged automatically).\n *\n * @throws {Error} If duplicate action or event names are detected\n */\n withSlice: <\n TNewSchemaReg extends SchemaRegister<TNewActions>,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n TNewMap extends Record<string, Schema>,\n TNewLanes extends string,\n >(\n slice: Slice<\n TNewSchemaReg,\n TNewEvents,\n TNewActions,\n TNewMap,\n Actor,\n TNewLanes\n >\n ) => ActBuilder<\n TSchemaReg & TNewSchemaReg,\n TEvents & TNewEvents,\n TActions & TNewActions,\n TStateMap & TNewMap,\n TActor,\n TLanes | TNewLanes\n >;\n /**\n * Locks a custom actor type for this application.\n *\n * This is a pure type-level method — it returns the same builder at\n * runtime but narrows the `TActor` generic so that `app.do()` and\n * reaction dispatchers require the richer actor shape.\n *\n * @template TNewActor - Custom actor type extending base Actor\n * @returns The same builder with `TActor` locked to `TNewActor`\n *\n * @example\n * ```typescript\n * type MyActor = { id: string; name: string; role: string; tenantId: string };\n *\n * const app = act()\n * .withActor<MyActor>()\n * .withState(Counter)\n * .build();\n *\n * // Now app.do() requires MyActor in the target\n * await app.do(\"increment\", {\n * stream: \"counter-1\",\n * actor: { id: \"1\", name: \"Alice\", role: \"admin\", tenantId: \"t1\" }\n * }, { by: 5 });\n * ```\n */\n withActor: <TNewActor extends Actor>() => ActBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TNewActor,\n TLanes\n >;\n /**\n * Declares a drain lane (ACT-1103). Lane name narrows `TLanes` so\n * `.to({lane})` and `ActOptions.onlyLanes` type-check against it.\n *\n * @example\n * ```typescript\n * const app = act()\n * .withState(Counter)\n * .withLane({ name: \"slow\", leaseMillis: 60_000, streamLimit: 5 })\n * .on(\"OrderConfirmed\")\n * .do(deliverWebhook)\n * .to({ target: \"webhooks-out\", lane: \"slow\" })\n * .build();\n * ```\n */\n withLane: <const TConfig extends LaneConfig>(\n config: TConfig\n ) => ActBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TActor,\n TLanes | TConfig[\"name\"]\n >;\n /**\n * Builds and returns the Act orchestrator instance.\n *\n * @param options - Optional runtime overrides (see {@link ActOptions}).\n * `options.onlyLanes` is narrowed to the declared `TLanes` union, so\n * `onlyLanes: [\"typo\"]` is a compile error when the lane wasn't\n * declared via `.withLane(...)`.\n * @returns The Act orchestrator instance\n *\n * @see {@link Act} for available orchestrator methods\n */\n build: (\n options?: ActOptions<TLanes>\n ) => Act<TSchemaReg, TEvents, TActions, TStateMap, TActor>;\n}\n\n/* eslint-disable @typescript-eslint/no-empty-object-type -- {} used as generic defaults */\n\n/**\n * Creates a new Act orchestrator builder for composing event-sourced applications.\n *\n * @example Basic application with single state\n * ```typescript\n * const app = act()\n * .withState(Counter)\n * .build();\n * ```\n *\n * @example Application with custom actor type\n * ```typescript\n * type MyActor = { id: string; name: string; role: string };\n *\n * const app = act()\n * .withActor<MyActor>()\n * .withState(Counter)\n * .build();\n * ```\n *\n * @example Application with slices (vertical slice architecture)\n * ```typescript\n * const CounterSlice = slice()\n * .withState(Counter)\n * .on(\"Incremented\")\n * .do(async (event) => { console.log(\"incremented!\"); })\n * .to(\"counter-target\")\n * .build();\n *\n * const app = act()\n * .withSlice(CounterSlice)\n * .build();\n * ```\n *\n *\n * @see {@link ActBuilder} for available builder methods\n * @see {@link Act} for orchestrator API methods\n * @see {@link state} for defining states\n * @see {@link slice} for defining slices\n */\nexport function act<\n // @ts-expect-error empty schema\n TSchemaReg extends SchemaRegister<TActions> = {},\n TEvents extends Schemas = {},\n TActions extends Schemas = {},\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n>(): ActBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor> {\n // Mutable runtime state — one set of references shared across the entire\n // fluent chain. Each `with*` / `on` call mutates these and returns the\n // same builder cast to the widened generic; type fanout is preserved\n // through the public type signatures, runtime allocation is not.\n const states = new Map<string, State<any, any, any>>();\n // Caches behind registry.sensitive_fields / registry.disclosure_predicate /\n // registry.deprecated_events / registry.autoclose_policy. Populated\n // on the first .build() call.\n const _sf = new Map<string, readonly string[]>();\n // Prebuilt default-deny read gates, one per sensitive event. Non-sensitive\n // events are absent → `query_gate` falls back to the shared IDENTITY_GATE.\n const _qg = new Map<string, EventGate>();\n const _dp = new Map<string, (event: any, actor: Actor) => boolean>();\n const _de = new Map<string, ReadonlySet<string>>();\n const _ac = new Map<\n string,\n (stream: string, head: any, count: number) => boolean\n >();\n const _aa = new Map<string, (stream: string, head: any) => Promise<void>>();\n const EMPTY_DEPRECATED: ReadonlySet<string> = new Set();\n const registry: Registry<TSchemaReg, TEvents, TActions> = {\n actions: {} as Registry<TSchemaReg, TEvents, TActions>[\"actions\"],\n events: {} as Registry<TSchemaReg, TEvents, TActions>[\"events\"],\n sensitive_fields: (event_name) => _sf.get(event_name) ?? [],\n query_gate: (event_name) => _qg.get(event_name) ?? IDENTITY_GATE,\n disclosure_predicate: (state_name) => _dp.get(state_name) ?? null,\n deprecated_events: (state_name) => _de.get(state_name) ?? EMPTY_DEPRECATED,\n autoclose_policy: (state_name) => _ac.get(state_name) ?? null,\n autoclose_archiver: (state_name) => _aa.get(state_name) ?? null,\n };\n const pending_projections: Projection<any>[] = [];\n const fold_projections: Projection<any>[] = [];\n const batch_handlers = new Map<string, BatchHandler<any>>();\n // Validated fold-projection ingredients, resolved once on the first\n // build. The HANDLERS themselves are built per `.build()` — see\n // `make_batch_handlers` — because a fold handler owns a mutable\n // per-stream cache that must never be shared across Acts.\n const fold_specs: {\n target: string;\n merged: any;\n flush: any;\n config: any;\n }[] = [];\n const lanes: LaneConfig[] = [];\n\n // Set on the first `.build()` call. Lets the same builder produce\n // many Acts (multi-tenant / A-B testing patterns) without re-merging\n // projections or re-logging the deprecation advisory.\n let _built = false;\n\n /**\n * Wraps a batch handler so the batch dispatcher stays PII-unaware —\n * sensitive keys are stripped from every event before the handler\n * sees it. `_sf` is read lazily at dispatch time, by when the\n * events pass has populated it.\n */\n const pii_wrap =\n (original: BatchHandler<any>) => async (events: any[], stream: string) => {\n const stripped = events.map((e) => {\n const f = _sf.get(e.name as string);\n return f ? pii_strip(e, f) : e;\n });\n return original(stripped as never, stream);\n };\n\n /**\n * Per-Act batch-handler map. Stateless projection handlers are shared\n * with the builder (they carry no state, and `register_batch_handler`\n * already rejects duplicate targets); state-projection FOLD handlers\n * are constructed fresh for every `.build()`.\n *\n * A fold handler owns a mutable per-stream cache of folded state\n * (`projection-fold.ts`), keyed on stream name alone. Sharing one\n * instance across Acts built from the same builder — the documented\n * multi-tenant pattern, and every `fixture(builder)` test — let one\n * Act's folded rows surface in another Act's sink, and made the\n * frontier guard compare event ids originating in different stores.\n * The cache still spans drain cycles within one Act, so the warm-fold\n * performance property is unchanged.\n *\n * Building here also means each Act's fold handlers observe that\n * build's own `patch_fn` (`validateFoldedState` is a per-build\n * option), instead of freezing the first build's choice.\n */\n const make_batch_handlers = (patch_fn: PatchFn) => {\n const handlers = new Map(batch_handlers);\n for (const spec of fold_specs) {\n handlers.set(\n spec.target,\n pii_wrap(\n make_fold_handler(\n spec.merged,\n spec.flush,\n spec.config,\n patch_fn,\n // Head loads strip sensitive keys like the warm path (#1320).\n (event_name) => _sf.get(event_name) ?? []\n )\n ) as never\n );\n }\n return handlers;\n };\n\n // ACT-403: auto-deprecation enforcement. Groups each state's events\n // by base name + `_v<digits>`; the highest version is current, all\n // lower ones are deprecated. Stashes the deprecation set on the\n // registry (`registry.deprecated_events(state_name)`) so the\n // orchestrator can warn post-commit when an action emits one.\n // Scans static `.emit(\"X\")` markers across every state and throws\n // if any target a deprecated event — the only legitimate use of a\n // deprecated event is on the reduce path. Finally, surfaces a\n // one-line startup advisory so operators can see \"your app has\n // legacy events kept for the read path, here's where they live.\"\n const finalize_deprecations = () => {\n const deprecation_summary: Array<{\n state_name: string;\n deprecated: string;\n current: string;\n }> = [];\n for (const state of states.values()) {\n const event_names = Object.keys(state.events);\n const deprecated = deprecated_event_names(event_names);\n if (deprecated.size === 0) continue;\n _de.set(state.name, deprecated);\n for (const name of deprecated) {\n // `current_version_of` is guaranteed non-undefined here — `name`\n // is in `deprecated`, which by construction means a higher-\n // versioned sibling exists in the same group.\n const current = current_version_of(name, event_names) as string;\n deprecation_summary.push({\n state_name: state.name,\n deprecated: name,\n current,\n });\n }\n for (const [action_name, handler] of Object.entries(state.on)) {\n const static_target = (handler as { _static_emit?: string } | undefined)\n ?._static_emit;\n if (static_target && deprecated.has(static_target)) {\n const current = current_version_of(static_target, event_names);\n throw new Error(\n `Action \"${action_name}\" in state \"${state.name}\" emits deprecated event \"${static_target}\". ` +\n `A newer version exists: \"${current}\". Update the .emit() call ` +\n `to target the current version. The reducer (.patch) for ` +\n `\"${static_target}\" stays as-is — historical events still need it.`\n );\n }\n }\n }\n if (deprecation_summary.length > 0) {\n const list = deprecation_summary\n .map(\n (d) =>\n `\"${d.deprecated}\" (current: \"${d.current}\", state: \"${d.state_name}\")`\n )\n .join(\", \");\n log().info(\n `Act registered ${deprecation_summary.length} deprecated event(s): ${list}. ` +\n `These are legacy versions kept for the read path. Consider truncating ` +\n `closed streams via app.close() when feasible to reduce historical event load. ` +\n `See docs/docs/architecture/event-schema-evolution.md.`\n );\n }\n };\n\n // The `as` chain on `self` is the type fanout: each fluent method\n // mutates state and returns `self` cast to its post-call generic\n // signature. Internal-only — public types stay narrow.\n const builder: ActBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor> =\n {\n withState: (state) => {\n register_state(state, states, registry.actions, registry.events);\n return builder as never;\n },\n withSlice: (input) => {\n for (const s of input.states.values()) {\n register_state(s, states, registry.actions, registry.events);\n }\n merge_event_register(registry.events, input.events);\n pending_projections.push(...input.projections);\n for (const slice_lane of input.lanes) {\n const existing = lanes.find((l) => l.name === slice_lane.name);\n if (!existing) {\n lanes.push(slice_lane);\n continue;\n }\n if (\n existing.leaseMillis !== slice_lane.leaseMillis ||\n existing.streamLimit !== slice_lane.streamLimit ||\n existing.cycleMs !== slice_lane.cycleMs\n ) {\n throw new Error(\n `Lane \"${slice_lane.name}\" was already declared with a different config`\n );\n }\n }\n return builder as never;\n },\n withProjection: (proj) => {\n merge_projection(proj as Projection<any>, registry.events);\n register_batch_handler(proj as Projection<any>, batch_handlers);\n if ((proj as Projection<any>).fold)\n fold_projections.push(proj as Projection<any>);\n return builder;\n },\n withActor: <TNewActor extends Actor>() =>\n builder as unknown as ActBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TNewActor\n >,\n withLane: (config) => {\n // Validate the lane bag at declaration (a bad leaseMillis/streamLimit\n // throws ZodError at build, not on the first cycle).\n register_lane(resolveLaneConfig(config), lanes);\n return builder as never;\n },\n on: <TKey extends keyof TEvents>(event: TKey) =>\n reaction_on(event, registry.events, builder) as never,\n build: (options?: ActOptions) => {\n // Validate the top-level scalar knobs at build (the nested autoclose /\n // circuitBreaker bags are validated by their own resolvers). A bad\n // maxSubscribedStreams / settleDebounceMs throws ZodError here.\n resolveActConfig(options);\n // ACT-1238: select the per-event patch step ONCE here — the\n // single selection site. `bare_patch` (the literal pre-#1238\n // `patch()` merge) when `validateFoldedState` is off, else\n // `validating_patch`. The same selected value feeds BOTH the\n // projection-fold handlers below and `build_es` (via the Act\n // constructor), so the command/load paths and the projection\n // path share one choice and neither branches per event.\n const patch_fn: PatchFn =\n options?.validateFoldedState === true ? validating_patch : bare_patch;\n // One-time finalize: merge pending projections and run the\n // deprecation scan + advisory log exactly once. Calling\n // `.build({scoped: ...})` repeatedly (e.g., per tenant) is\n // supported — see extension-points.md § Scoped ports. Without\n // this guard, `merge_projection` would re-add reactions to the\n // shared registry on every call (accumulating `_p`/`_p_p`\n // dedupe suffixes), and the deprecation advisory would log on\n // every tenant.\n if (!_built) {\n for (const proj of pending_projections) {\n merge_projection(proj, registry.events as Record<string, any>);\n register_batch_handler(proj, batch_handlers);\n if (proj.fold) fold_projections.push(proj);\n }\n // State projections fold the registry-merged FULL state — the\n // builder only recorded intent. Resolve here, where every\n // partial has merged, and refuse silently-partial folds: the\n // projection's register must cover the state's whole register.\n // The `patch_fn` selected once at the top of `build()` feeds the\n // fold handlers, matching the command/load paths (ACT-1238).\n for (const proj of fold_projections) {\n const fold = proj.fold!;\n const merged = states.get(fold.name);\n if (!merged)\n throw new Error(\n `State projection \"${proj.target}\" folds \"${fold.name}\", which is not registered — add it via withState/withSlice before build()`\n );\n const missing = Object.keys(merged.events).filter(\n (event_name) => !(event_name in proj.events)\n );\n if (missing.length > 0)\n throw new Error(\n `State projection \"${proj.target}\" of \"${fold.name}\" is missing events ${missing.join(\", \")} — pass every partial of the state to .of()`\n );\n // A target may be claimed exactly once, by a batch handler OR by\n // a fold — `make_batch_handlers` does an unconditional\n // `handlers.set(spec.target, …)`, so without this the last\n // registration silently won (#1440).\n //\n // `register_batch_handler` cannot catch these: it early-returns\n // on `!proj.batchHandler`, and a fold projection has a target but\n // no batch handler, so the fold path bypassed the guard in both\n // directions. The damage was worse than a dead projection — the\n // fold cold-loads the losing target's streams through the\n // stream-keyed cache, so it received the OTHER projection's\n // aggregates and wrote them into its own read table.\n //\n // With this check all four {batch, fold}² pairings throw;\n // previously only batch × batch did.\n if (\n batch_handlers.has(proj.target!) ||\n fold_specs.some((s) => s.target === proj.target)\n )\n throw new Error(\n `Duplicate projection target \"${proj.target}\" — a target is served by one batch handler or one state projection, never both`\n );\n // Record the validated ingredients only. The handler is\n // constructed per `.build()` (see `make_batch_handlers`) — it\n // owns a mutable per-stream fold cache, so one shared instance\n // would leak folded rows between Acts built from this builder.\n fold_specs.push({\n target: proj.target!,\n merged,\n flush: fold.flush,\n config: fold.config,\n });\n }\n finalize_deprecations();\n validate_lane_references(registry, lanes);\n // Precompute the sensitive-field lookup. Iterates each registered\n // event's Zod schema exactly once at build; later commit/load paths\n // hit the cache in O(1). Events with no sensitive fields don't get\n // Build the sensitive-data wiring in three passes (#855):\n //\n // - events pass: precompute the sensitive-field lookup `_sf` from\n // each event's Zod schema; while we're already walking events,\n // wrap their registered reaction handlers so `build_handle`\n // stays PII-unaware.\n // - states pass: snapshot the disclosure predicates into `_dp`,\n // reject `.snap()` on sensitive-bearing states, and build the\n // per-state step delegates the orchestrator calls (`me.view`,\n // `me.message`, wrapped `me.patch[name]`).\n // - batch_handlers pass: wrap each batch handler so the batch\n // dispatcher stays PII-unaware.\n //\n // The orchestrator calls three step delegates per event:\n // - `me.message(validated)` — produces the commit-bound shape\n // (`{name, data, pii?}`) from a validated emit.\n // - `me.patch[event_name](event, state)` — the reducer that\n // derives the next state from the committed event.\n // - `me.view(event, actor)` — produces the caller-visible form\n // (snapshot.event).\n //\n // For PII-free states (the common case) `view` and `message` are\n // bound to identity in `state-builder.ts` and `patch` is the\n // user-declared reducer; the orchestrator's hot path is identical\n // to the pre-#855 code at runtime. For PII-aware states (≥1\n // `sensitive(...)` event), each delegate is rebound to fold the\n // gate / split / merge into the step itself.\n for (const [event_name, reg] of Object.entries(\n registry.events as Record<\n string,\n {\n schema: import(\"zod\").ZodType;\n reactions: Map<string, { handler: any }>;\n }\n >\n )) {\n const fields = pii_fields(reg.schema);\n if (fields.length === 0) continue;\n _sf.set(event_name, fields);\n // Prebuild the default-deny read gate once, capturing `fields`.\n // The actor-less read surfaces (`query`/`query_array`) resolve it\n // by name; non-sensitive events never reach here, so they fall\n // back to the shared IDENTITY_GATE — zero per-event cost.\n _qg.set(event_name, make_gate(fields, null));\n // Strip PII from the event payload before reactions see it.\n for (const [name, reaction] of reg.reactions) {\n const inner = reaction.handler;\n const wrapped = (event: any, stream: string, app: any) =>\n inner(pii_strip(event, fields), stream, app);\n // Preserve handler.name — build_handle asserts on named functions.\n Object.defineProperty(wrapped, \"name\", { value: inner.name });\n reaction.handler = wrapped;\n reg.reactions.set(name, reaction as never);\n }\n }\n for (const state of states.values()) {\n if (state.disclose) _dp.set(state.name, state.disclose);\n if (state.autoclose) _ac.set(state.name, state.autoclose);\n if (state.archive) _aa.set(state.name, state.archive);\n const fields_by_event = new Map<string, readonly string[]>();\n for (const event_name of Object.keys(state.events)) {\n const fields = _sf.get(event_name);\n if (fields) fields_by_event.set(event_name, fields);\n }\n if (fields_by_event.size === 0) continue; // pure — keep state-builder defaults\n // Snapshots write derived state into `__snapshot__.data`, which\n // `forget_pii` cannot reach. Reject the combination at build so\n // the misconfiguration surfaces in dev/CI, not as a silent leak\n // past the GDPR boundary months later.\n if (state.snap) {\n const offending = [...fields_by_event.keys()];\n throw new Error(\n `State \"${state.name}\" cannot snapshot — events {${offending.join(\", \")}} carry sensitive fields. ` +\n \"Snapshots write derived state into __snapshot__.data, which forget_pii cannot reach. \" +\n \"Remove .snap() or remove sensitive(...) markers.\"\n );\n }\n const disclose = state.disclose ?? null;\n state.pii_aware = true;\n // Prebuild one actor-aware read gate per sensitive event, capturing\n // this state's disclosure predicate — the same `make_gate`\n // primitive the query path uses (predicate-less there). A pii-aware\n // state can still declare non-sensitive events; those aren't in\n // `view_gates`, so `state.view` falls back to the shared\n // IDENTITY_GATE — no per-event field lookup, no `?? []` allocation.\n const view_gates = new Map<string, EventGate>();\n for (const [event_name, fields] of fields_by_event) {\n view_gates.set(event_name, make_gate(fields, disclose));\n }\n state.view = (event, actor) =>\n (view_gates.get(event.name as string) ?? IDENTITY_GATE)(\n event,\n actor\n );\n state.message = (validated) => {\n const fields = fields_by_event.get(validated.name as string);\n return fields ? pii_split(validated, fields) : validated;\n };\n }\n for (const [target, original] of batch_handlers) {\n batch_handlers.set(target, pii_wrap(original) as never);\n }\n // Synthesize the autoclose reactions last, once the registry is\n // fully merged — their dynamic resolvers must be present before\n // the orchestrator classifies the registry. The window/cadence\n // knobs resolve from this first build() call's options; repeat\n // builds (per-tenant scoped Acts) share the registry and the\n // synthesized reaction with it.\n synthesize_autoclose_reactions(\n registry,\n states,\n resolveAutocloseConfig(options ?? {})\n );\n // The registry is complete: freeze the containers so any later\n // registration or orchestrator-side mutation throws instead of\n // silently diverging from what was classified. (Reaction maps\n // remain Map instances — the freeze guards the object shape,\n // convention guards the maps.)\n Object.freeze(registry.actions);\n Object.freeze(registry.events);\n Object.freeze(registry);\n _built = true;\n }\n\n return new Act<TSchemaReg, TEvents, TActions, TStateMap, TActor>(\n registry,\n states,\n make_batch_handlers(patch_fn),\n options,\n lanes,\n patch_fn\n );\n },\n events: registry.events,\n };\n return builder;\n}\n","/**\n * @module projection-builder\n * @category Builders\n *\n * Fluent builder for composing projection handlers — read-model updaters\n * that react to events and update external state (databases, caches, etc.).\n *\n * Projections differ from slices: they don't contain states, don't dispatch\n * actions, and are pure side-effect handlers routed to a named stream.\n */\nimport type { ZodType } from \"zod\";\nimport {\n _this_,\n type FoldConfig,\n resolveFoldConfig,\n} from \"../internal/index.js\";\nimport type {\n BatchHandler,\n CacheEntry,\n Committed,\n EventRegister,\n FoldOptions,\n Reaction,\n ReactionResolver,\n Schema,\n Schemas,\n State,\n} from \"../types/index.js\";\n\n/**\n * A self-contained projection grouping read-model update handlers.\n * Projections are composed into an Act orchestrator via `act().withProjection(projection)`.\n *\n * @template TEvents - Event schemas handled by this projection\n */\nexport type Projection<TEvents extends Schemas> = {\n readonly _tag: \"Projection\";\n readonly events: EventRegister<TEvents>;\n readonly target?: string;\n readonly batchHandler?: BatchHandler<TEvents>;\n /**\n * State-fold spec from `.of()`. The builder only records intent — the\n * orchestrator resolves the REGISTRY-MERGED full state at\n * `act().build()` and synthesizes the batch handler there, so the\n * fold always covers every reducer of the state, including partials\n * merged by slices the projection never saw.\n * @internal\n */\n readonly fold?: {\n readonly name: string;\n readonly flush: (rows: ReadonlyArray<CacheEntry<any>>) => Promise<void>;\n readonly config: FoldConfig;\n };\n};\n\n/**\n * The `.of()` continuation: state projections flush the cache layer\n * outward — the rows ARE the streams' {@link CacheEntry} values, one\n * per dirty stream per flush round. Must be an idempotent upsert keyed\n * on `stream` (guard with `event_id` for order safety when a rebuild\n * races a live worker).\n */\ntype FoldFlush<TState extends Schema, TE extends Schemas> = {\n flush: (\n handler: (rows: ReadonlyArray<CacheEntry<TState>>) => Promise<void>\n ) => {\n build: () => Projection<TE>;\n };\n};\n\n/**\n * `.of()` accepts the partials of ONE state (same name, enforced at the\n * type level via `TName`) purely for typing and event registration —\n * the fold itself always runs on the registry-merged full state,\n * resolved at `act().build()`. Passing every partial is required: the\n * orchestrator validates completeness at build and throws on missing\n * events.\n */\ntype OfSignatures = {\n <\n TS1 extends Schema,\n TE1 extends Schemas,\n TA1 extends Schemas,\n TN extends string,\n >(\n s1: State<TS1, TE1, TA1, TN>,\n options?: FoldOptions\n ): FoldFlush<TS1, TE1>;\n <\n TS1 extends Schema,\n TE1 extends Schemas,\n TA1 extends Schemas,\n TS2 extends Schema,\n TE2 extends Schemas,\n TA2 extends Schemas,\n TN extends string,\n >(\n s1: State<TS1, TE1, TA1, TN>,\n s2: State<TS2, TE2, TA2, TN>,\n options?: FoldOptions\n ): FoldFlush<TS1 & TS2, TE1 & TE2>;\n <\n TS1 extends Schema,\n TE1 extends Schemas,\n TA1 extends Schemas,\n TS2 extends Schema,\n TE2 extends Schemas,\n TA2 extends Schemas,\n TS3 extends Schema,\n TE3 extends Schemas,\n TA3 extends Schemas,\n TN extends string,\n >(\n s1: State<TS1, TE1, TA1, TN>,\n s2: State<TS2, TE2, TA2, TN>,\n s3: State<TS3, TE3, TA3, TN>,\n options?: FoldOptions\n ): FoldFlush<TS1 & TS2 & TS3, TE1 & TE2 & TE3>;\n <\n TS1 extends Schema,\n TE1 extends Schemas,\n TA1 extends Schemas,\n TS2 extends Schema,\n TE2 extends Schemas,\n TA2 extends Schemas,\n TS3 extends Schema,\n TE3 extends Schemas,\n TA3 extends Schemas,\n TS4 extends Schema,\n TE4 extends Schemas,\n TA4 extends Schemas,\n TN extends string,\n >(\n s1: State<TS1, TE1, TA1, TN>,\n s2: State<TS2, TE2, TA2, TN>,\n s3: State<TS3, TE3, TA3, TN>,\n s4: State<TS4, TE4, TA4, TN>,\n options?: FoldOptions\n ): FoldFlush<TS1 & TS2 & TS3 & TS4, TE1 & TE2 & TE3 & TE4>;\n};\n\n/** Helper: a single-key record mapping an event name to its Zod schema. */\ntype EventEntry<TKey extends string = string, TData extends Schema = Schema> = {\n [P in TKey]: ZodType<TData>;\n};\n\n/** Infer the handler-result type after registering one event. */\ntype DoResult<\n TEvents extends Schemas,\n TKey extends string,\n TData extends Schema,\n TTarget extends string | undefined = undefined,\n> = ProjectionBuilder<TEvents & { [P in TKey]: TData }, TTarget, true> & {\n to: (\n resolver: ReactionResolver<TEvents & { [P in TKey]: TData }, TKey> | string\n ) => ProjectionBuilder<TEvents & { [P in TKey]: TData }, TTarget, true>;\n};\n\n/**\n * Fluent builder interface for composing projections.\n *\n * When a static target is provided via `projection(\"target\")`, the builder\n * exposes a `.batch()` method for registering a batch handler that processes\n * all events in a single call.\n *\n * @template TEvents - Event schemas\n * @template TTarget - Static target string or undefined\n */\nexport type ProjectionBuilder<\n TEvents extends Schemas,\n TTarget extends string | undefined = undefined,\n THasHandlers extends boolean = false,\n> = {\n /**\n * Begins defining a projection handler for a specific event.\n *\n * Pass a `{ EventName: schema }` record — use shorthand `{ EventName }`\n * when the variable name matches the event name. The key becomes the\n * event name, the value the Zod schema.\n */\n on: <TKey extends string, TData extends Schema>(\n entry: EventEntry<TKey, TData>\n ) => {\n do: (\n handler: (\n event: Committed<TEvents & { [P in TKey]: TData }, TKey>,\n stream: string\n ) => Promise<void>\n ) => DoResult<TEvents, TKey, TData, TTarget>;\n };\n /**\n * Builds and returns the Projection data structure.\n */\n build: () => Projection<TEvents>;\n /**\n * The registered event schemas and their reaction maps.\n */\n readonly events: EventRegister<TEvents>;\n} & (TTarget extends string\n ? {\n /**\n * Registers a batch handler that processes all events in a single call.\n *\n * Only available on projections with a static target (`projection(\"target\")`).\n * The handler receives a discriminated union of all declared events,\n * enabling bulk DB operations in a single transaction.\n *\n * When defined, the batch handler is always called — even for a single event.\n * Individual `.do()` handlers serve as fallback for projections without `.batch()`.\n */\n batch: (handler: BatchHandler<TEvents>) => {\n build: () => Projection<TEvents>;\n };\n } & (THasHandlers extends false\n ? {\n /**\n * Declares a state projection: fold every event of the given\n * state through its own reducers and flush one row per stream —\n * the queryable list of the aggregates themselves.\n *\n * The state is the filter: the projection consumes exactly the\n * state's event register, so in a multi-state app only that\n * state's streams are folded — and every event of a folded\n * stream reaches the reducer. Write amplification tracks the\n * distinct stream count, not the event count; `app.reset`\n * rebuilds in O(streams) upserts.\n *\n * The fluent chain enforces the shape: `.of()` is only offered\n * before any `.on()` handler, and narrows to `.flush()` +\n * `.build()` — a projection either folds a state or declares\n * handlers, never both.\n */\n of: OfSignatures;\n }\n : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {})\n : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {});\n\n/* eslint-disable @typescript-eslint/no-empty-object-type -- {} used as generic defaults */\n\n/**\n * Creates a new projection builder for composing read-model update handlers.\n *\n * Projections enable separation of read-model concerns from command handling.\n * Each `.on({ Event }).do(handler)` call registers a handler that updates\n * a projection (database table, cache, etc.) in response to events.\n *\n * Pass a target stream name to `projection(\"target\")` so every handler\n * inherits that resolver automatically. Omit it and use per-handler\n * `.to()` when handlers route to different streams.\n *\n * @param target - Optional default target stream for all handlers\n *\n * @example Default target (all handlers routed to \"tickets\")\n * ```typescript\n * const TicketProjection = projection(\"tickets\")\n * .on({ TicketOpened })\n * .do(async ({ stream, data }) => {\n * await db.insert(tickets).values({ id: stream, ...data });\n * })\n * .on({ TicketClosed })\n * .do(async ({ stream, data }) => {\n * await db.update(tickets).set(data).where(eq(tickets.id, stream));\n * })\n * .build();\n * ```\n *\n * @example Per-handler routing\n * ```typescript\n * const MultiProjection = projection()\n * .on({ OrderPlaced })\n * .do(async (event) => { ... })\n * .to(\"orders\")\n * .on({ PaymentReceived })\n * .do(async (event) => { ... })\n * .to(\"payments\")\n * .build();\n * ```\n *\n * @see {@link ProjectionBuilder} for builder methods\n * @see {@link Projection} for the output type\n */\n/**\n * @internal Build the core builder object (shared between overloads). One\n * mutable `events` register threaded through every fluent call; .on()\n * mutates and returns the same builder cast to its widened generic.\n */\nfunction _projection<\n TEvents extends Schemas,\n TTarget extends string | undefined,\n>(target: TTarget): ProjectionBuilder<TEvents, TTarget> {\n const events = {} as EventRegister<TEvents>;\n const default_resolver: { target: string } | undefined =\n typeof target === \"string\" ? { target } : undefined;\n\n // Mutable runtime bag — typed loosely; the public projection() return\n // type narrows back to the user-facing `ProjectionBuilder<TEvents, TTarget>`.\n\n const base: any = {\n on: <TKey extends string, TData extends Schema>(\n entry: EventEntry<TKey, TData>\n ) => {\n const keys = Object.keys(entry);\n if (keys.length !== 1) throw new Error(\".on() requires exactly one key\");\n const event = keys[0] as TKey;\n const schema = entry[event];\n\n // Register the event schema if not already present\n if (!(event in events)) {\n (events as Record<string, unknown>)[event] = {\n schema,\n reactions: new Map(),\n };\n }\n\n return {\n do: (\n handler: (\n event: Committed<TEvents & { [P in TKey]: TData }, TKey>,\n stream: string\n ) => Promise<void>\n ) => {\n const reaction: Reaction<TEvents & { [P in TKey]: TData }, TKey> = {\n handler,\n resolver: default_resolver ?? _this_,\n options: {\n blockOnError: true,\n maxRetries: 3,\n },\n };\n const register = (events as Record<string, any>)[event];\n if (!handler.name)\n throw new Error(\n `Projection handler for \"${event}\" must be a named function`\n );\n if (register.reactions.has(handler.name))\n throw new Error(\n `Duplicate projection handler \"${handler.name}\" for event \"${event}\". ` +\n `Projection handlers are keyed by function name; rename one of them.`\n );\n register.reactions.set(handler.name, reaction);\n\n // Same builder, widened generic — no recursive call.\n const widened = base as unknown as ProjectionBuilder<\n TEvents & { [P in TKey]: TData },\n TTarget\n >;\n return Object.assign(widened, {\n to(\n resolver:\n | ReactionResolver<TEvents & { [P in TKey]: TData }, TKey>\n | string\n ) {\n // Patch the same reaction in place — no second Map.set().\n reaction.resolver =\n typeof resolver === \"string\" ? { target: resolver } : resolver;\n return widened;\n },\n });\n },\n };\n },\n build: () => ({\n _tag: \"Projection\" as const,\n events,\n ...(target !== undefined && { target }),\n }),\n events,\n };\n\n // Add .batch() and .of() only for static-target projections\n if (typeof target === \"string\") {\n return Object.assign(base, {\n batch: (handler: BatchHandler<TEvents>) => ({\n build: () => ({\n _tag: \"Projection\" as const,\n events,\n target,\n batchHandler: handler,\n }),\n }),\n of: (...args: unknown[]) => {\n if (Object.keys(events).length > 0)\n throw new Error(\n `Projection \"${target}\" mixes .of() with .on() handlers — a projection either folds a state or declares handlers, never both`\n );\n // Trailing options bag is the only non-State argument.\n const is_state = (a: unknown): a is State<Schema, Schemas, Schemas> =>\n !!a &&\n typeof (a as State<Schema, Schemas, Schemas>).init === \"function\";\n const partials = args.filter(is_state);\n const options = (args.find((a) => !is_state(a)) ?? {}) as FoldOptions;\n if (partials.length === 0)\n throw new Error(`Projection \"${target}\" .of() requires a state`);\n const name = partials[0].name;\n for (const partial of partials)\n if (partial.name !== name)\n throw new Error(\n `Projection \"${target}\" .of() partials must share one state name — got \"${name}\" and \"${partial.name}\"`\n );\n // Misconfiguration surfaces here, at startup — not on first drain.\n const config = resolveFoldConfig(options);\n // The partials' own schema instances register the events, so the\n // same-name declarations in slices pass the identity check in\n // merge_event_register. The named no-op reaction routes fetches\n // to this target; dispatch always goes through the batch handler\n // the orchestrator synthesizes from the registry-merged state.\n const fold_events = {} as EventRegister<Schemas>;\n for (const partial of partials)\n for (const [event_name, schema] of Object.entries(partial.events)) {\n if (event_name in fold_events) continue;\n const noop = {\n [`${target}_fold`]: async () => {},\n }[`${target}_fold`] as (\n event: Committed<Schemas, string>,\n stream: string\n ) => Promise<void>;\n (fold_events as Record<string, unknown>)[event_name] = {\n schema,\n reactions: new Map([\n [\n `${target}_fold`,\n {\n handler: noop,\n resolver: { target },\n options: { blockOnError: true, maxRetries: 3 },\n },\n ],\n ]),\n };\n }\n return {\n flush: (\n handler: (rows: ReadonlyArray<CacheEntry<Schema>>) => Promise<void>\n ) => ({\n build: () => ({\n _tag: \"Projection\" as const,\n events: fold_events,\n target,\n fold: { name, flush: handler, config },\n }),\n }),\n };\n },\n }) as ProjectionBuilder<TEvents, TTarget>;\n }\n\n return base as ProjectionBuilder<TEvents, TTarget>;\n}\n\n/**\n * Creates a new projection builder with a static target stream.\n *\n * All handlers inherit the target resolver automatically. Enables `.batch()`\n * for bulk event processing in a single transaction.\n *\n * @param target - Static target stream for all handlers\n */\nexport function projection<TEvents extends Schemas = {}>(\n target: string\n): ProjectionBuilder<TEvents, string>;\n/**\n * Creates a new projection builder without a default target.\n *\n * Use per-handler `.to()` to route events to different streams.\n */\nexport function projection<TEvents extends Schemas = {}>(\n target?: undefined\n): ProjectionBuilder<TEvents, undefined>;\nexport function projection<TEvents extends Schemas = {}>(\n target?: string\n): ProjectionBuilder<TEvents, string | undefined> {\n return _projection<TEvents, string | undefined>(target);\n}\n","/**\n * @module slice-builder\n * @category Builders\n *\n * Fluent builder for composing partial states with scoped reactions into\n * self-contained functional slices (vertical slice architecture).\n */\nimport {\n reaction_on,\n register_lane,\n register_state,\n} from \"../internal/index.js\";\nimport type { DEFAULT_LANE } from \"../ports.js\";\nimport type {\n Actor,\n EventRegister,\n LaneConfig,\n Schema,\n SchemaRegister,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport type { BuilderBase } from \"./builder-base.js\";\nimport type { Projection } from \"./projection-builder.js\";\n\n/**\n * A self-contained functional slice grouping partial states with their\n * scoped reactions. Slices are composed into an Act orchestrator via\n * `act().withSlice(slice)`.\n *\n * @template TSchemaReg - Schema register for states\n * @template TEvents - Event schemas from this slice's states\n * @template TActions - Action schemas from this slice's states\n * @template TStateMap - Map of state names to state schemas\n * @template TActor - Actor type extending base Actor\n */\nexport type Slice<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n TLanes extends string = typeof DEFAULT_LANE,\n> = {\n readonly _tag: \"Slice\";\n readonly states: Map<string, State<any, any, any>>;\n readonly events: EventRegister<TEvents>;\n readonly projections: ReadonlyArray<Projection<any>>;\n /**\n * Drain lanes declared on this slice via `.withLane(...)` (ACT-1103).\n * `act().withSlice(slice)` merges these into the Act's lane set so\n * `.to({lane})` is statically checked at the slice's call site against\n * the lanes the slice itself declared.\n */\n readonly lanes: ReadonlyArray<LaneConfig>;\n /** @internal phantom field for type-level state schema tracking */\n readonly _S?: TSchemaReg;\n /** @internal phantom field for type-level state name tracking */\n readonly _M?: TStateMap;\n /** @internal phantom field for type-level actor tracking */\n readonly _TActor?: TActor;\n /** @internal phantom field for type-level lane union tracking */\n readonly _TLanes?: TLanes;\n};\n\n/**\n * Fluent builder interface for composing functional slices.\n *\n * Provides a chainable API for registering states and projections,\n * and defining reactions scoped to the slice's own events.\n *\n * @template TSchemaReg - Schema register for states\n * @template TEvents - Event schemas\n * @template TActions - Action schemas\n * @template TStateMap - Map of state names to state schemas\n * @template TActor - Actor type extending base Actor\n */\nexport interface SliceBuilder<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n TLanes extends string = typeof DEFAULT_LANE,\n> extends BuilderBase<\n SliceBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor, TLanes>,\n TEvents,\n TActions,\n TActor,\n TLanes\n > {\n /**\n * Registers a state definition with the slice.\n *\n * Include every state whose actions your reaction handlers need to\n * dispatch. Duplicate registrations (same state in multiple slices)\n * are handled automatically at composition time.\n */\n withState: <\n TNewState extends Schema,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n TNewName extends string = string,\n >(\n state: State<TNewState, TNewEvents, TNewActions, TNewName>\n ) => SliceBuilder<\n TSchemaReg & { [K in keyof TNewActions]: TNewState },\n TEvents & TNewEvents,\n TActions & TNewActions,\n TStateMap & { [K in TNewName]: TNewState },\n TActor,\n TLanes\n >;\n /**\n * Declares a drain lane on this slice (ACT-1103). Merged into the\n * parent Act's lane set by `act().withSlice(slice)`.\n */\n withLane: <const TConfig extends LaneConfig>(\n config: TConfig\n ) => SliceBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TActor,\n TLanes | TConfig[\"name\"]\n >;\n /**\n * Builds and returns the Slice data structure.\n */\n build: () => Slice<TSchemaReg, TEvents, TActions, TStateMap, TActor, TLanes>;\n}\n\n/* eslint-disable @typescript-eslint/no-empty-object-type -- {} used as generic defaults */\n\n/**\n * Creates a new slice builder for composing partial states with scoped reactions.\n *\n * Slices enable vertical slice architecture by grouping related states and\n * reactions into self-contained feature modules. Reactions defined in a slice\n * are type-scoped to events from that slice's states only.\n *\n * @example Single-state slice with typed dispatch\n * ```typescript\n * const CounterSlice = slice()\n * .withState(Counter)\n * .on(\"Incremented\")\n * .do(async (event, _stream, app) => {\n * await app.do(\"reset\", target, {});\n * })\n * .to(\"counter-target\")\n * .build();\n * ```\n *\n * @example Cross-state dispatch (include both states)\n * ```typescript\n * const CreationSlice = slice()\n * .withState(TicketCreation)\n * .withState(TicketOperations) // handler can dispatch AssignTicket\n * .on(\"TicketOpened\").do(async (event, _stream, app) => {\n * await app.do(\"AssignTicket\", target, payload, { reactingTo: event });\n * })\n * .build();\n * ```\n *\n * @see {@link SliceBuilder} for builder methods\n * @see {@link Slice} for the output type\n */\nexport function slice<\n // @ts-expect-error empty schema\n TSchemaReg extends SchemaRegister<TActions> = {},\n TEvents extends Schemas = {},\n TActions extends Schemas = {},\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n>(): SliceBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor> {\n // One mutable state shared across the entire fluent chain. Each\n // `withState` / `withProjection` / `on` call mutates these and returns\n // the same builder cast to the widened generic; type fanout is preserved\n // through the public type signatures, runtime allocation is not.\n const states = new Map<string, State<any, any, any>>();\n const actions: Record<string, any> = {};\n const events = {} as EventRegister<TEvents>;\n const projections: Projection<any>[] = [];\n const lanes: LaneConfig[] = [];\n\n const builder: SliceBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TActor\n > = {\n withState: (state) => {\n register_state(state, states, actions, events as Record<string, unknown>);\n return builder as never;\n },\n withProjection: (proj) => {\n projections.push(proj as Projection<any>);\n return builder;\n },\n withLane: (config) => {\n register_lane(config, lanes);\n return builder as never;\n },\n on: <TKey extends keyof TEvents>(event: TKey) =>\n reaction_on(event, events, builder) as never,\n build: () => ({\n _tag: \"Slice\" as const,\n states,\n events,\n projections,\n lanes,\n }),\n events,\n };\n return builder;\n}\n","/**\n * @module state-builder\n * @category Builders\n *\n * Fluent interface for defining a strongly-typed state machine using Zod schemas.\n */\nimport type { ZodType } from \"zod\";\nimport {\n type AutoclosePolicy,\n compile_autoclose_policy,\n policy_keep_days,\n policy_min_after_days,\n resolveActionConfig,\n} from \"../internal/index.js\";\nimport type {\n ActionHandler,\n ActionOptions,\n Actor,\n AutocloseArchiver,\n AutoclosePredicate,\n Committed,\n GivenHandlers,\n Invariant,\n PassthroughPatchHandler,\n PatchHandlers,\n Schema,\n Schemas,\n Snapshot,\n State,\n ZodTypes,\n} from \"../types/index.js\";\n\n/**\n * Builder interface for defining a state with event sourcing.\n *\n * Provides a fluent API to configure the initial state, event types,\n * and event handlers (reducers) before moving to action configuration.\n *\n * @template TState - State schema type\n * @template TName - State name literal type\n *\n * @see {@link state} for usage examples\n * @see {@link ActionBuilder} for action configuration\n */\nexport type StateBuilder<\n TState extends Schema,\n TName extends string = string,\n> = {\n /**\n * Defines the initial state for new state instances.\n *\n * The init function is called when a new stream is created (first event).\n * It can accept initial data or return a default state.\n *\n * @param init - Function returning the initial state\n * @returns A builder with `.emits()` to declare event types\n *\n * @example\n * ```typescript\n * .init(() => ({ count: 0, created: new Date() }))\n * ```\n *\n * @example With initial data\n * ```typescript\n * .init((data) => ({ ...data, createdAt: new Date() }))\n * ```\n */\n init: (init: () => Readonly<TState>) => {\n /**\n * Declares the event types that this state can emit.\n *\n * Events represent facts that have happened - they should be named in past tense.\n * Each event is defined with a Zod schema for type safety and runtime validation.\n *\n * @template TEvents - Event schemas type\n * @param events - Object mapping event names to Zod schemas\n * @returns An ActionBuilder (with optional `.patch()` to override specific reducers)\n *\n * @example\n * ```typescript\n * .emits({\n * Incremented: z.object({ amount: z.number() }),\n * Decremented: z.object({ amount: z.number() }),\n * Reset: z.object({})\n * })\n * ```\n */\n emits: <TEvents extends Schemas>(\n events: ZodTypes<TEvents>\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- {} avoids string index signature that Record<string, never> would add, keeping keyof A precise\n ) => ActionBuilder<TState, TEvents, {}, TName> & {\n /**\n * Overrides specific event reducers. Events without a custom patch\n * default to passthrough: `({ data }) => data` (event data merges\n * into state).\n *\n * @param patch - Partial map of event names to patch handler functions\n * @returns An ActionBuilder for defining actions\n *\n * @example Only override the events that need custom logic\n * ```typescript\n * .emits({ TicketOpened, TicketClosed, TicketResolved })\n * .patch({\n * TicketOpened: ({ data }) => {\n * const { message, messageId, userId, ...other } = data;\n * return { ...other, userId, messages: { [messageId]: { ... } } };\n * },\n * })\n * // TicketClosed and TicketResolved use passthrough\n * ```\n */\n patch: (\n patch: Partial<PatchHandlers<TState, TEvents>>\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- {} avoids string index signature that Record<string, never> would add, keeping keyof A precise\n ) => ActionBuilder<TState, TEvents, {}, TName>;\n };\n };\n};\n\n/** Helper: a single-key record mapping a state name to its Zod schema. */\ntype StateEntry<\n TKey extends string = string,\n TState extends Schema = Schema,\n> = {\n [P in TKey]: ZodType<TState>;\n};\n\n/** Helper: a single-key record mapping an action name to its Zod schema. */\ntype ActionEntry<\n TKey extends string = string,\n TNewActions extends Schema = Schema,\n> = {\n [P in TKey]: ZodType<TNewActions>;\n};\n\n/**\n * Builder interface for defining actions (commands) on a state.\n *\n * Actions represent user/system intents to modify state. Each action is validated\n * against a schema, can have business rule invariants, and must emit one or more events.\n *\n * @template TState - State schema type\n * @template TEvents - Event schemas type\n * @template TActions - Action schemas type\n * @template TName - State name literal type\n * @template TSnap - `true` once `.snap(...)` has been called. Gates the\n * `.autocloses({ keep })` rolling-window option — a windowed close is\n * meaningless without snapshots, so `keep` only typechecks after\n * `.snap` in the chain.\n *\n * @see {@link state} for complete usage examples\n */\nexport type ActionBuilder<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TName extends string = string,\n TSnap extends boolean = false,\n> = {\n /**\n * Defines an action (command) that can be executed on this state.\n *\n * Actions represent intents to change state - they should be named in imperative form\n * (e.g., \"CreateUser\", \"IncrementCounter\", \"PlaceOrder\"). Actions are validated against\n * their schema and must emit at least one event.\n *\n * Pass a `{ ActionName: schema }` record — use shorthand `{ ActionName }`\n * when the variable name matches the action name. The key becomes the\n * action name, the value the Zod schema.\n *\n * Pass an optional second argument to declare a per-action retry\n * policy — the orchestrator retries this action on\n * {@link ConcurrencyError} up to `maxRetries` extra times, applying\n * `backoff` between attempts when set. Omit the argument to keep the\n * current single-attempt behavior (`ConcurrencyError` surfaces on\n * first conflict).\n *\n * @template TKey - Action name (string literal type)\n * @template TNewActions - Action payload schema type\n * @param entry - Single-key record `{ ActionName: schema }`\n * @param options - Optional per-action retry policy\n * ({@link ActionOptions}).\n * @returns An object with `.given()` and `.emit()` for further configuration\n *\n * @example Simple action without invariants\n * ```typescript\n * .on({ increment: z.object({ by: z.number() }) })\n * .emit((action) => [\"Incremented\", { amount: action.by }])\n * ```\n *\n * @example Hot-stream action with retry + jittered exponential backoff\n * ```typescript\n * .on(\n * { transfer: z.object({ amount: z.number() }) },\n * {\n * maxRetries: 5,\n * backoff: { strategy: \"exponential\", baseMs: 10, maxMs: 200, jitter: true },\n * }\n * )\n * .emit((action) => [\"Transferred\", { amount: action.amount }])\n * ```\n *\n * @example Action with business rules\n * ```typescript\n * .on({ withdraw: z.object({ amount: z.number() }) })\n * .given([\n * { description: \"Account must be open\", valid: (state) => state.status === \"open\" },\n * { description: \"Funds must be available\", valid: (state) => state.balance > 0 }\n * ])\n * .emit((action) => [\"Withdrawn\", { amount: action.amount }])\n * ```\n *\n * @example Action with shorthand (variable name matches action name)\n * ```typescript\n * const OpenTicket = z.object({ title: z.string() });\n * .on({ OpenTicket })\n * .emit((action) => [\"TicketOpened\", { title: action.title }])\n * ```\n */\n on: <TKey extends string, TNewActions extends Schema>(\n entry: ActionEntry<TKey, TNewActions>,\n options?: ActionOptions\n ) => {\n /**\n * Adds business rule invariants that must hold before the action can execute.\n *\n * Invariants are checked after loading the current state but before emitting\n * events. Each invariant pairs a `description` with a `valid(state, actor?)`\n * predicate — when a predicate returns `false`, the action throws\n * `InvariantError` carrying the description. All invariants must pass for\n * the action to succeed.\n *\n * @param rules - Array of {@link Invariant} objects (`{ description, valid }`)\n * @returns An object with `.emit()` to finalize the action\n *\n * @example\n * ```typescript\n * .given([\n * { description: \"Must be active\", valid: (state) => state.status === \"active\" },\n * { description: \"Must be the owner\", valid: (state, actor) => state.ownerId === actor?.id }\n * ])\n * ```\n */\n given: (rules: Invariant<TState>[]) => {\n /**\n * Defines the action handler that emits events.\n *\n * The handler receives the action payload and current state snapshot,\n * and must return one or more events to emit. Events are applied to state\n * via the patch handlers defined earlier.\n *\n * Pass a string event name for passthrough: the action payload becomes\n * the event data directly.\n *\n * @param handler - Function that returns events to emit, or event name string for passthrough\n * @returns The ActionBuilder for chaining more actions\n *\n * @example Custom handler\n * ```typescript\n * .emit((action, snapshot) => {\n * const newBalance = snapshot.state.balance + action.amount;\n * return [\"Deposited\", { amount: action.amount, newBalance }];\n * })\n * ```\n *\n * @example Passthrough (action payload = event data)\n * ```typescript\n * .emit(\"TicketAssigned\")\n * ```\n */\n emit: {\n /** Custom handler — receives `(action, snapshot)` and returns one\n * or more `[EventName, data]` tuples (or `undefined`). */\n (\n handler: ActionHandler<\n TState,\n TEvents,\n { [P in TKey]: TNewActions },\n TKey\n >\n ): ActionBuilder<\n TState,\n TEvents,\n TActions & { [P in TKey]: TNewActions },\n TName,\n TSnap\n >;\n /** Passthrough — the action payload becomes the event data\n * directly. Must reference an event declared in `.emits()`. */\n (\n event_name: keyof TEvents & string\n ): ActionBuilder<\n TState,\n TEvents,\n TActions & { [P in TKey]: TNewActions },\n TName,\n TSnap\n >;\n };\n };\n /**\n * Defines the action handler that emits events. Same two overloads as\n * the post-`.given()` form above:\n *\n * - **Function** — receives `(action, snapshot)` and returns one or\n * more `[EventName, data]` tuples (or `undefined`).\n * - **String** — passthrough: the action payload becomes the event\n * data directly. Must reference an event declared in `.emits()`.\n *\n * The two overloads are kept separate (rather than merged into a\n * `handler | string` union) so that TS contextual typing of the\n * function alternative isn't degraded by considering the string\n * branch — under the union form `TState` could collapse to its\n * `Schema` constraint inside the callback.\n *\n * @example Passthrough (action payload = event data)\n * ```typescript\n * .emit(\"Incremented\")\n * ```\n *\n * @example Single event\n * ```typescript\n * .emit((action) => [\"Incremented\", { amount: action.by }])\n * ```\n *\n * @example Multiple events\n * ```typescript\n * .emit((action) => [\n * [\"Incremented\", { amount: action.by }],\n * [\"LogUpdated\", { message: `Incremented by ${action.by}` }]\n * ])\n * ```\n */\n emit: {\n (\n handler: ActionHandler<\n TState,\n TEvents,\n { [P in TKey]: TNewActions },\n TKey\n >\n ): ActionBuilder<\n TState,\n TEvents,\n TActions & { [P in TKey]: TNewActions },\n TName,\n TSnap\n >;\n (\n event_name: keyof TEvents & string\n ): ActionBuilder<\n TState,\n TEvents,\n TActions & { [P in TKey]: TNewActions },\n TName,\n TSnap\n >;\n };\n };\n /**\n * Defines a snapshotting strategy to optimize state reconstruction.\n *\n * Snapshots store the current state at a point in time, allowing faster state loading\n * by avoiding replaying all events from the beginning. The snap function is called\n * after each event is applied and should return `true` when a snapshot should be taken.\n *\n * @param snap - Predicate function that returns true when a snapshot should be taken\n * @returns The ActionBuilder for chaining\n *\n * @example Snapshot every 10 events\n * ```typescript\n * .snap((snapshot) => snapshot.patches >= 10)\n * ```\n *\n * @example Snapshot based on state size\n * ```typescript\n * .snap((snapshot) => {\n * const estimatedSize = JSON.stringify(snapshot.state).length;\n * return estimatedSize > 10000 || snapshot.patches >= 50;\n * })\n * ```\n *\n * @example Time-based snapshotting\n * ```typescript\n * .snap((snapshot) => {\n * const hoursSinceLastSnapshot = snapshot.patches * 0.1; // Estimate\n * return hoursSinceLastSnapshot >= 24;\n * })\n * ```\n */\n snap: (\n snap: (snapshot: Snapshot<TState, TEvents>) => boolean\n ) => ActionBuilder<TState, TEvents, TActions, TName, true>;\n /**\n * Declares the disclosure predicate for `sensitive(...)`-marked event\n * fields. Gates external reads: returning `true` allows the actor to see\n * plaintext on the event; returning `false` substitutes `\"[REDACTED]\"`.\n * When absent, the framework default-denies on every external read —\n * fail-safe.\n *\n * One predicate per state. A second `.discloses(...)` call replaces the\n * first (same shape as snapshots being state-level, not per-event).\n *\n * The predicate receives the full event including merged PII so it can\n * branch on the payload itself (e.g.\n * `event.data.ownerId === actor.id`). Reducers, projections, and\n * reactions are unaffected — they follow separate visibility rules\n * documented in #855.\n *\n * @param disclose - Predicate `(event, actor) => boolean`. `true` =\n * plaintext, `false` = `\"[REDACTED]\"` substitution.\n * @returns The ActionBuilder for chaining.\n *\n * @example Owner-or-admin disclosure\n * ```typescript\n * state({ User: userSchema })\n * .init(() => ({ ... }))\n * .emits({ UserRegistered: z.object({ email: sensitive(z.string()) }) })\n * .discloses((event, actor) =>\n * actor.id === event.stream || actor.roles?.includes(\"admin\"))\n * ```\n */\n discloses: (\n disclose: (\n event: Committed<TEvents, keyof TEvents & string>,\n actor: Actor\n ) => boolean\n ) => ActionBuilder<TState, TEvents, TActions, TName, TSnap>;\n /**\n * Declares the online close predicate for this state. The\n * orchestrator's autoclose cycle iterates the state's streams once\n * per tick and calls the predicate per candidate; truthy results are\n * scheduled for atomic truncate-and-seed via `Store.truncate` on the\n * next batch.\n *\n * One predicate per state. A second `.autocloses(...)` call replaces\n * the first (same shape as `.snap` / `.discloses` — state-level, not\n * per-event). Absent → the state opts out of online close entirely;\n * the cycle skips it and pays zero per-tick cost for it.\n *\n * Pass a declarative {@link AutoclosePolicy} object literal covering the\n * three operational pressure points (`after`, `is`, `reaches`). Top-level\n * fields combine with AND; an optional `or: {...}` block opens an\n * alternative OR path. Validated via Zod at build time; misconfiguration\n * throws before `act().build()` completes.\n *\n * Under the hood this compiles to a synthesized reaction (#1090) that runs\n * on a per-aggregate synthetic stream: it defers to `head.created + the\n * policy's min after` while the cooldown holds and closes the stream once\n * the policy matches. There is no background sweep.\n *\n * **The function-predicate form was removed (#1090).** `.autocloses` no\n * longer accepts `(stream, head, count) => boolean`; an opaque predicate has\n * no derivable due-time or terminal event to react to. For conditions the\n * declarative form can't express, call `app.close(...)` from your own logic.\n *\n * @param policy The declarative {@link AutoclosePolicy} bag.\n * @returns The ActionBuilder for chaining.\n *\n * @example Declarative — cooldown after terminal (a Ticket closes\n * 90 days after resolution).\n * ```typescript\n * .autocloses({ is: \"TicketResolved\", after: { days: 90 } })\n * ```\n *\n * @example Declarative — multi-terminal (an Order closes on any of\n * three terminal events, no cooldown).\n * ```typescript\n * .autocloses({ is: [\"Shipped\", \"Delivered\", \"Cancelled\"] })\n * ```\n *\n * @example Declarative — time-only retention (a Session closes\n * after 24h regardless of head event).\n * ```typescript\n * .autocloses({ after: { days: 1 } })\n * ```\n *\n * @example Declarative — pure cardinality cap.\n * ```typescript\n * .autocloses({ reaches: 10_000 })\n * ```\n *\n * @example Declarative — primary cooldown + safety-net backstop.\n * ```typescript\n * .autocloses({\n * is: \"TicketResolved\", // primary trigger\n * after: { days: 90 }, // AND aged 90 days\n * or: { reaches: 10_000 }, // OR cardinality safety net\n * })\n * ```\n *\n * @example Declarative — pure OR (only backstops, no primary\n * cooldown).\n * ```typescript\n * .autocloses({ or: { is: \"TicketResolved\", reaches: 10_000 } })\n * ```\n *\n * @example Rolling window — keep the last 180 days of real events on a\n * live stream (requires `.snap(...)` earlier in the chain; `keep`\n * won't typecheck without it). Each eligible cycle prunes the prefix\n * below the closest safe snapshot older than `now − keep`.\n * ```typescript\n * .snap((s) => s.patches >= 100)\n * .autocloses({ keep: { days: 180 } })\n * ```\n *\n * @example Terminate AND prune — close 90 days after resolution,\n * meanwhile keep open streams pruned to a 180-day window.\n * ```typescript\n * .snap((s) => s.patches >= 100)\n * .autocloses({ is: \"TicketResolved\", after: { days: 90 }, keep: { days: 180 } })\n * ```\n */\n autocloses: (\n policy: [TSnap] extends [true]\n ? AutoclosePolicy\n : Omit<AutoclosePolicy, \"keep\"> & {\n /** Rolling-window retention requires `.snap(...)` earlier in\n * the builder chain — a windowed close prunes behind a real\n * snapshot, so a state that never snapshots has nothing to\n * prune behind. */\n keep?: never;\n }\n ) => ActionBuilder<TState, TEvents, TActions, TName, TSnap>;\n /**\n * Declares the archiver the online close cycle runs **before**\n * truncating a stream this state's `.autocloses(...)` predicate\n * accepted. Hosts use it to write events to durable storage (S3,\n * an analytics warehouse, cold tier) before the tombstone lands,\n * so the truncate doesn't lose history that the operator still\n * needs.\n *\n * Threads into `CloseTarget.archive` via the same plumbing\n * `app.close({ stream, archive })` already uses — the cycle holds\n * the stream's guard while the archiver runs, and a thrown\n * archiver leaves the stream guarded but un-truncated. No partial\n * truncate state, no data loss; the cycle retries the candidate\n * on the next tick.\n *\n * One archiver per state. A second `.archives(...)` call replaces\n * the first (same shape as `.snap` / `.discloses` /\n * `.autocloses`). Absent → the cycle truncates without an archive\n * step.\n *\n * @param archive `(stream, head) => Promise<void>`. Runs while\n * the stream is locked against new writes; the truncate runs\n * immediately after a successful resolve.\n * @returns The ActionBuilder for chaining.\n *\n * @example Archive to S3 before truncate.\n * ```typescript\n * state({ Ticket: ticketSchema })\n * .emits({ TicketOpened, TicketResolved })\n * // ...\n * .autocloses({ is: \"TicketResolved\" })\n * .archives(async (stream) => {\n * const events = await loadEvents(stream);\n * await s3.upload(`tickets/${stream}.jsonl`, events);\n * })\n * ```\n */\n archives: (\n archive: AutocloseArchiver<TEvents>\n ) => ActionBuilder<TState, TEvents, TActions, TName, TSnap>;\n /**\n * Finalizes and builds the state definition.\n *\n * Call this method after defining all actions, invariants, and patches to create\n * the complete State object that can be registered with Act.\n *\n * @returns The complete strongly-typed State definition\n *\n * @example\n * ```typescript\n * const Counter = state({ Counter: schema })\n * .init(() => ({ count: 0 }))\n * .emits({ Incremented: z.object({ amount: z.number() }) })\n * .patch({ Incremented: ({ data }, state) => ({ count: state.count + data.amount }) })\n * .on({ increment: z.object({ by: z.number() }) })\n * .emit((action) => [\"Incremented\", { amount: action.by }])\n * .build(); // Returns State<TState, TEvents, TActions, TName>\n * ```\n */\n build: () => State<TState, TEvents, TActions, TName>;\n};\n\n/**\n * Creates a new state definition with event sourcing capabilities.\n *\n * States are the core building blocks of Act. Each state represents a consistency\n * boundary (aggregate) that processes actions, emits events, and maintains its own\n * state through event patches (reducers). States use event sourcing to maintain a\n * complete audit trail and enable time-travel capabilities.\n *\n * The state builder provides a fluent API for defining:\n * 1. Initial state via `.init()`\n * 2. Event types via `.emits()` — all events default to passthrough (`({ data }) => data`)\n * 3. Custom event reducers via `.patch()` (optional — only for events that need custom logic)\n * 4. Actions (commands) via `.on()` → `.emit()` — pass an event name string for passthrough\n * 5. Business rules (invariants) via `.given()`\n * 6. Snapshotting strategy via `.snap()`\n *\n * @template TState - Zod schema type defining the shape of the state\n * @param entry - Single-key record mapping state name to Zod schema (e.g., `{ Counter: z.object({ count: z.number() }) }`)\n * @returns A StateBuilder instance for fluent API configuration\n *\n * @example Basic counter state (with custom patch)\n * ```typescript\n * import { state } from \"@rotorsoft/act\";\n * import { z } from \"zod\";\n *\n * const Counter = state({ Counter: z.object({ count: z.number() }) })\n * .init(() => ({ count: 0 }))\n * .emits({\n * Incremented: z.object({ amount: z.number() })\n * })\n * .patch({ // optional — only for events needing custom reducers\n * Incremented: ({ data }, state) => ({ count: state.count + data.amount })\n * })\n * .on({ increment: z.object({ by: z.number() }) })\n * .emit((action) => [\"Incremented\", { amount: action.by }])\n * .build();\n * ```\n *\n * @example Passthrough state (no custom patch or emit needed)\n * ```typescript\n * const DigitBoard = state({ DigitBoard: z.object({ digit: z.string() }) })\n * .init(() => ({ digit: \"\" }))\n * .emits({ DigitCounted: z.object({ digit: z.string() }) })\n * // no .patch() — passthrough is the default (event data merges into state)\n * .on({ CountDigit: z.object({ digit: z.string() }) })\n * .emit(\"DigitCounted\") // string passthrough — action payload becomes event data\n * .build();\n * ```\n *\n * @example State with multiple events and invariants\n * ```typescript\n * const BankAccount = state({ BankAccount: z.object({\n * balance: z.number(),\n * currency: z.string(),\n * status: z.enum([\"open\", \"closed\"])\n * }) })\n * .init(() => ({ balance: 0, currency: \"USD\", status: \"open\" }))\n * .emits({\n * Deposited: z.object({ amount: z.number() }),\n * Withdrawn: z.object({ amount: z.number() }),\n * Closed: z.object({})\n * })\n * .patch({ // only override events needing custom logic\n * Deposited: ({ data }, state) => ({ balance: state.balance + data.amount }),\n * Withdrawn: ({ data }, state) => ({ balance: state.balance - data.amount }),\n * Closed: () => ({ status: \"closed\", balance: 0 })\n * })\n * .on({ deposit: z.object({ amount: z.number() }) })\n * .given([\n * { description: \"Account must be open\", valid: (state) => state.status === \"open\" }\n * ])\n * .emit(\"Deposited\") // passthrough — action payload { amount } becomes event data\n * .on({ withdraw: z.object({ amount: z.number() }) })\n * .given([\n * { description: \"Account must be open\", valid: (state) => state.status === \"open\" },\n * { description: \"Funds must be available\", valid: (state) => state.balance > 0 }\n * ])\n * .emit(\"Withdrawn\")\n * .on({ close: z.object({}) })\n * .given([\n * { description: \"Account must be open\", valid: (state) => state.status === \"open\" },\n * { description: \"Balance must be zero\", valid: (state) => state.balance === 0 }\n * ])\n * .emit(\"Closed\")\n * .build();\n * ```\n *\n * @example State with snapshotting\n * ```typescript\n * const User = state({ User: z.object({\n * name: z.string(),\n * email: z.string(),\n * loginCount: z.number()\n * }) })\n * .init((data) => ({ ...data, loginCount: 0 }))\n * .emits({\n * UserCreated: z.object({ name: z.string(), email: z.string() }),\n * UserLoggedIn: z.object({})\n * })\n * .patch({ // only override events needing custom logic\n * UserLoggedIn: (_, state) => ({ loginCount: state.loginCount + 1 })\n * })\n * // UserCreated uses passthrough — event data merges into state\n * .on({ createUser: z.object({ name: z.string(), email: z.string() }) })\n * .emit(\"UserCreated\") // passthrough\n * .on({ login: z.object({}) })\n * .emit(\"UserLoggedIn\")\n * .snap((snap) => snap.patches >= 10) // Snapshot every 10 events\n * .build();\n * ```\n *\n * @see {@link StateBuilder} for available builder methods\n * @see {@link ActionBuilder} for action configuration methods\n * @see {@link https://rotorsoft.github.io/act-root/docs/intro | Getting Started Guide}\n * @see {@link https://rotorsoft.github.io/act-root/docs/examples/calculator | Calculator Example}\n */\nexport function state<TName extends string, TState extends Schema>(\n entry: StateEntry<TName, TState>\n): StateBuilder<TState, TName> {\n const keys = Object.keys(entry);\n if (keys.length !== 1) throw new Error(\"state() requires exactly one key\");\n const name = keys[0] as TName;\n const state_schema = (entry as Record<string, ZodType<TState>>)[name];\n return {\n init(init) {\n return {\n emits<TEvents extends Schema>(events: ZodTypes<TEvents>) {\n // Default passthrough patches: event data merges into state\n const default_patch = Object.fromEntries(\n Object.keys(events).map((k) => {\n const fn = Object.assign(({ data }: { data: any }) => data, {\n _passthrough: true as const,\n }) satisfies PassthroughPatchHandler;\n return [k, fn];\n })\n ) as unknown as PatchHandlers<TState, TEvents>;\n\n // Build one mutable state object the action_builder threads\n // through every fluent call. patch() (if invoked) just mutates\n // the patch map in place — no re-builder wasted.\n const internal: State<TState, TEvents, Schemas, TName> = {\n events,\n actions: {},\n state: state_schema,\n name,\n init,\n patch: default_patch,\n on: {},\n // Step delegates initialized as identity, `pii_aware` false.\n // `act().build()` flips both on states with `sensitive(...)`\n // events to bake in the gate / split and gate the cache write.\n pii_aware: false,\n view: (event) => event,\n message: (validated) => validated,\n };\n\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- {} avoids string index signature\n const builder = action_builder<TState, TEvents, {}, TName>(internal);\n\n return Object.assign(builder, {\n patch(customPatch: Partial<PatchHandlers<TState, TEvents>>) {\n Object.assign(internal.patch, customPatch);\n return builder;\n },\n });\n },\n };\n },\n };\n}\n\n/**\n * Internal action-builder. The runtime object is a single mutable bag —\n * each fluent call (`on`, `snap`) mutates it and returns the same builder\n * cast to the widened generic type. Type-level fanout is preserved; the\n * O(N) `{...state}` spreads per call are not.\n *\n * Generics are erased to `Schemas` at runtime — the cast on return narrows\n * back to the call-site's widened types.\n */\nfunction action_builder<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TName extends string = string,\n>(\n state: State<TState, TEvents, TActions, TName>\n): ActionBuilder<TState, TEvents, TActions, TName> {\n // The mutable bag — typed loosely since callers narrow on return.\n const internal = state as unknown as State<TState, TEvents, Schemas, TName>;\n\n const builder: ActionBuilder<TState, TEvents, TActions, TName> = {\n on<TKey extends string, TNewActions extends Schema>(\n entry: ActionEntry<TKey, TNewActions>,\n options?: ActionOptions\n ) {\n const keys = Object.keys(entry);\n if (keys.length !== 1) throw new Error(\".on() requires exactly one key\");\n const action = keys[0] as TKey;\n const schema = entry[action];\n\n if (action in internal.actions)\n throw new Error(`Duplicate action \"${action}\"`);\n\n type MergedActions = TActions & { [P in TKey]: TNewActions };\n (internal.actions as Record<string, ZodType<Schema>>)[action] = schema;\n if (options) {\n // #1269: validate the whole action bag at declaration so a bad\n // `maxRetries`/`backoff` throws ZodError at build, not a NaN gate.\n resolveActionConfig(options);\n internal.options ??= {};\n (internal.options as Record<string, ActionOptions>)[action] = options;\n }\n\n function given(rules: Invariant<TState>[]) {\n internal.given ??= {} as GivenHandlers<TState, Schemas>;\n (internal.given as Record<string, Invariant<TState>[]>)[action] = rules;\n return { emit };\n }\n\n function emit(\n handler:\n | ActionHandler<TState, TEvents, MergedActions, TKey>\n | (keyof TEvents & string)\n ) {\n if (typeof handler === \"string\") {\n const event_name = handler;\n // Tag the synthetic function with the static event name so\n // the act-builder can detect emissions of deprecated events\n // at build time (ACT-403). Dynamic forms — where the\n // returned event name is computed inside the user's\n // function — can't be inspected statically; they're caught\n // by the runtime warning in event-sourcing.ts.\n const emit_fn = Object.assign(\n (payload: any) => [event_name, payload],\n {\n _static_emit: event_name,\n }\n );\n (internal.on as Record<string, unknown>)[action] = emit_fn;\n } else {\n (internal.on as Record<string, unknown>)[action] = handler;\n }\n return builder as unknown as ActionBuilder<\n TState,\n TEvents,\n MergedActions,\n TName\n >;\n }\n\n return { given, emit };\n },\n\n snap(snap: (snapshot: Snapshot<TState, TEvents>) => boolean) {\n internal.snap = snap;\n // Flip the type-level TSnap flag — same runtime object, the cast\n // unlocks `.autocloses({ keep })` for the rest of the chain.\n return builder as unknown as ActionBuilder<\n TState,\n TEvents,\n TActions,\n TName,\n true\n >;\n },\n\n discloses(\n disclose: (\n event: Committed<TEvents, keyof TEvents & string>,\n actor: Actor\n ) => boolean\n ) {\n // Replace on every call — matches snap's state-level semantics. Operators\n // who need per-event differences branch inside the predicate.\n internal.disclose = disclose;\n return builder;\n },\n\n autocloses(policy: AutoclosePolicy) {\n // Declarative policy only (#1090). The online path is a synthesized\n // reaction that defers to a derivable due-time and closes — an opaque\n // function predicate has no terminal event to react to nor a window to\n // derive, so it's no longer accepted online. Operators who need custom\n // logic call `app.close(...)` from their own reaction.\n if (typeof policy === \"function\") {\n throw new Error(\n \".autocloses(fn) is no longer supported — pass a declarative policy \" +\n \"({ after, is, reaches, or }) or call app.close(...) from your own \" +\n \"reaction for custom logic.\"\n );\n }\n if (policy === null || typeof policy !== \"object\") {\n throw new Error(\n \".autocloses(...) requires a policy object; got \" + typeof policy\n );\n }\n // The type gate (`TSnap`) already rejects `keep` before `.snap` at\n // compile time; this is the equivalent guard for untyped callers.\n if ((policy as AutoclosePolicy).keep && !internal.snap) {\n throw new Error(\n \".autocloses({ keep }) requires .snap(...) earlier in the chain — a rolling window prunes behind a real snapshot, so a state that never snapshots has nothing to prune behind.\"\n );\n }\n // Replace on every call — matches snap / discloses state-level\n // semantics. Compile to the predicate the reaction evaluates, and\n // cache the policy's min `after` window so the reaction knows whether\n // to park on a due-time or wait for the next event; `keep` resolves\n // to the rolling-window width the reaction prunes against.\n internal.autoclose = compile_autoclose_policy(\n policy\n ) as AutoclosePredicate<TEvents>;\n internal.autoclose_after_days = policy_min_after_days(policy);\n internal.autoclose_keep_days = policy_keep_days(policy);\n return builder;\n },\n\n archives(archive: AutocloseArchiver<TEvents>) {\n if (typeof archive !== \"function\") {\n throw new Error(\n \".archives(archive) requires a function; got \" + typeof archive\n );\n }\n internal.archive = archive;\n return builder;\n },\n\n build(): State<TState, TEvents, TActions, TName> {\n return internal as unknown as State<TState, TEvents, TActions, TName>;\n },\n };\n return builder;\n}\n","/**\n * @module csv\n *\n * `CsvFile` — a single class implementing both {@link EventSource}\n * and {@link EventSink} so a CSV file on disk can be either side of\n * a transfer pipeline (ACT-1128 / #788).\n *\n * - As a source: streams one row at a time off a line interface;\n * the awaited per-event callback gives 1-event-in-flight\n * backpressure on reads.\n * - As a sink: serialized `WriteStream.write` await per row,\n * propagating I/O errors through the chunk callback.\n *\n * `commit` / `claim` / `subscribe` and the rest of `Store` are NOT\n * implemented — `CsvFile` is a transfer-only primitive, not a\n * store you'd run an Act app against.\n */\n\nimport { createReadStream, createWriteStream, type WriteStream } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport type {\n Committed,\n EventSink,\n EventSource,\n Query,\n Schemas,\n} from \"./types/action.js\";\nimport { dateReviver } from \"./utils.js\";\n\n/**\n * Construct a {@link CsvFile} from either a filesystem path (for\n * reading and/or writing through the OS) or an in-memory blob (a\n * pre-loaded CSV string, used by the inspector when a CSV arrives\n * over the wire via tRPC).\n *\n * Both modes share the same on-disk format, so the same blob shape\n * can be round-tripped through the transfer pipeline.\n */\nexport type CsvFileOptions = { path: string } | { blob: string };\n\n/**\n * Same column order as the inspector's backup endpoint, kept here\n * so `CsvFile` is round-trip-compatible with existing backups.\n */\nconst CSV_COLUMNS = [\n \"id\",\n \"name\",\n \"data\",\n \"stream\",\n \"version\",\n \"created\",\n \"meta\",\n] as const;\n\nexport class CsvFile implements EventSource, EventSink {\n private readonly path: string | null;\n private readonly blob: string | null;\n\n constructor(options: CsvFileOptions) {\n if (\"path\" in options) {\n this.path = options.path;\n this.blob = null;\n } else {\n this.path = null;\n this.blob = options.blob;\n }\n }\n\n async query<E extends Schemas>(\n callback: (event: Committed<E, keyof E>) => void,\n _filter?: Query\n ): Promise<number> {\n const lines =\n this.blob !== null ? linesFromBlob(this.blob) : linesFromFile(this.path!);\n let count = 0;\n let header: readonly string[] | null = null;\n for await (const line of lines) {\n if (!line.trim()) continue;\n const fields = parse_csv_line(line);\n if (!header) {\n header = fields;\n const expected = CSV_COLUMNS.join(\",\");\n if (header.join(\",\") !== expected)\n throw new Error(`Invalid CSV header. Expected: ${expected}`);\n continue;\n }\n if (fields.length !== CSV_COLUMNS.length)\n throw new Error(\n `Row ${count + 1}: expected ${CSV_COLUMNS.length} fields, got ${fields.length}`\n );\n const event: Committed<E, keyof E> = {\n id: Number.parseInt(fields[0]!, 10),\n name: fields[1]! as keyof E,\n // Revive dates like every Store adapter does — a Date in an event\n // payload must not depend on whether it came back through a store or\n // through a CSV restore (#1399). The `created` column below has\n // always been parsed explicitly; the JSON columns were missed.\n data: JSON.parse(fields[2]!, dateReviver),\n stream: fields[3]!,\n version: Number.parseInt(fields[4]!, 10),\n created: new Date(fields[5]!),\n meta: JSON.parse(fields[6]!, dateReviver),\n };\n await Promise.resolve(callback(event));\n count++;\n }\n if (header === null)\n throw new Error(\"CSV must have a header and at least one row\");\n return count;\n }\n\n async restore(\n driver: (\n callback: (event: Committed<Schemas, keyof Schemas>) => Promise<number>\n ) => Promise<void>\n ): Promise<void> {\n if (this.path === null)\n throw new Error(\n \"CsvFile in blob mode is read-only — provide `path` to write\"\n );\n const writer = createWriteStream(this.path, {\n flags: \"w\",\n encoding: \"utf8\",\n });\n let next_id = 1;\n try {\n await write_line(writer, CSV_COLUMNS.join(\",\"));\n await driver(async (event) => {\n const id = next_id++;\n const row = [\n String(id),\n csv_escape(event.name as string),\n csv_escape(JSON.stringify(event.data)),\n csv_escape(event.stream),\n String(event.version),\n event.created.toISOString(),\n csv_escape(JSON.stringify(event.meta)),\n ].join(\",\");\n await write_line(writer, row);\n return id;\n });\n } finally {\n await new Promise<void>((resolve) => writer.end(resolve));\n }\n }\n\n async dispose(): Promise<void> {\n // No-op: `restore` always closes its writer in a `finally`, and\n // blob mode never opens one. The Disposable contract is here to\n // make `CsvFile` interchangeable with `Store` in transfer\n // pipelines, not because the file handle outlives the call.\n }\n}\n\nasync function* linesFromFile(path: string): AsyncIterable<string> {\n const stream = createReadStream(path, { encoding: \"utf8\" });\n const rl = createInterface({\n input: stream,\n crlfDelay: Number.POSITIVE_INFINITY,\n });\n try {\n for await (const line of rl) yield line;\n } finally {\n rl.close();\n stream.close();\n }\n}\n\nasync function* linesFromBlob(blob: string): AsyncIterable<string> {\n let start = 0;\n while (start < blob.length) {\n const nl = blob.indexOf(\"\\n\", start);\n const end = nl === -1 ? blob.length : nl;\n yield blob.slice(start, end);\n start = nl === -1 ? blob.length : nl + 1;\n await Promise.resolve();\n }\n}\n\nfunction parse_csv_line(line: string): string[] {\n const fields: string[] = [];\n let i = 0;\n while (i < line.length) {\n if (line[i] === '\"') {\n let value = \"\";\n i++;\n while (i < line.length) {\n if (line[i] === '\"' && line[i + 1] === '\"') {\n value += '\"';\n i += 2;\n } else if (line[i] === '\"') {\n i++;\n break;\n } else {\n value += line[i++];\n }\n }\n fields.push(value);\n if (line[i] === \",\") i++;\n } else {\n const next = line.indexOf(\",\", i);\n if (next === -1) {\n fields.push(line.slice(i));\n i = line.length;\n } else {\n fields.push(line.slice(i, next));\n i = next + 1;\n }\n }\n }\n return fields;\n}\n\nfunction csv_escape(value: string): string {\n if (/[\",\\n\\r]/.test(value)) return `\"${value.replace(/\"/g, '\"\"')}\"`;\n return value;\n}\n\nfunction write_line(writer: WriteStream, line: string): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n writer.write(`${line}\\n`, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n"],"mappings":"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","names":["store","state","sensitive","deps","config","z","z","z","z","state","config","config","tombstone","load","snap","state","state","action","state","action","valid","action","block","config","cache","row","block","action","action","state","config","config","state","config","state","action","snap"]}
1
+ {"version":3,"sources":["../src/signals.ts","../src/act.ts","../src/internal/event-versions.ts","../src/internal/walk-streams.ts","../src/internal/audit.ts","../src/internal/autoclose-policy.ts","../src/internal/autoclose-window.ts","../src/internal/close-signal.ts","../src/internal/defer-signal.ts","../src/internal/autoclose-reaction.ts","../src/internal/build-classify.ts","../src/internal/config.ts","../src/internal/defer-config.ts","../src/internal/merge.ts","../src/internal/builder-utils.ts","../src/internal/circuit-breaker.ts","../src/internal/close-cycle.ts","../src/internal/correlate-cycle.ts","../src/internal/correlator.ts","../src/internal/drain-cycle.ts","../src/internal/defer-timer.ts","../src/internal/drain-ratio.ts","../src/internal/drain.ts","../src/internal/event-sourcing.ts","../src/internal/backoff.ts","../src/internal/tracing.ts","../src/internal/projection-fold.ts","../src/internal/reactions.ts","../src/internal/settle.ts","../src/builders/act-builder.ts","../src/builders/projection-builder.ts","../src/builders/slice-builder.ts","../src/builders/state-builder.ts","../src/csv.ts"],"sourcesContent":["import { disposeAndExit, log } from \"./ports.js\";\n\n// Resolve the logger lazily inside each handler — calling log() here at\n// module load would register the default ConsoleLogger before user code\n// can inject (port singletons are first-call-wins).\nprocess.once(\"SIGINT\", async (arg?: any) => {\n log().info(arg, \"SIGINT\");\n await disposeAndExit(\"EXIT\");\n});\nprocess.once(\"SIGTERM\", async (arg?: any) => {\n log().info(arg, \"SIGTERM\");\n await disposeAndExit(\"EXIT\");\n});\nprocess.once(\"uncaughtException\", async (arg?: any) => {\n log().error(arg, \"Uncaught Exception\");\n await disposeAndExit(\"ERROR\");\n});\nprocess.once(\"unhandledRejection\", async (arg?: any) => {\n log().error(arg, \"Unhandled Rejection\");\n await disposeAndExit(\"ERROR\");\n});\n","import EventEmitter from \"node:events\";\nimport {\n ALL_LANES,\n type AuditDeps,\n audit,\n bare_patch,\n build_drain,\n build_es,\n build_handle,\n build_handle_batch,\n CircuitBreaker,\n type CircuitBreakerOptions,\n type CircuitState,\n CorrelateCycle,\n classify_registry,\n close_correlation,\n DrainController,\n type DrainOps,\n default_correlator,\n type EsOps,\n type EventLaneSet,\n type Handle,\n type HandleBatch,\n type PatchFn,\n register_weak_disposer,\n resolveCircuitBreakerConfig,\n resolveDrainConfig,\n resolveSettleConfig,\n run_close_cycle,\n SettleLoop,\n scan,\n walk_streams,\n} from \"./internal/index.js\";\n\n// Public re-exports: these appear in ActOptions / ActLifecycleEvents above.\nexport type { CircuitBreakerOptions, CircuitState } from \"./internal/index.js\";\n\nimport {\n cache,\n log,\n type Scoped,\n scoped,\n store,\n TOMBSTONE_EVENT,\n} from \"./ports.js\";\nimport type {\n Actor,\n AsOf,\n AuditCategory,\n AuditFinding,\n AuditOptions,\n BatchHandler,\n BlockedLease,\n CloseResult,\n CloseTarget,\n Committed,\n Correlator,\n DoOptions,\n Drain,\n DrainOptions,\n EventSink,\n EventSource,\n IAct,\n LaneConfig,\n Lease,\n LoadTarget,\n Logger,\n Query,\n Registry,\n ScanOptions,\n ScanResult,\n Schema,\n SchemaRegister,\n Schemas,\n SettleOptions,\n Snapshot,\n State,\n Store,\n StoreNotification,\n StreamFilter,\n StreamPosition,\n Target,\n} from \"./types/index.js\";\n\n/**\n * @category Orchestrator\n * @see Store\n *\n * Main orchestrator for event-sourced state machines and workflows.\n *\n * It manages the lifecycle of actions, reactions, and event streams, providing APIs for loading state, executing actions, querying events, and draining reactions.\n *\n * ## Usage\n *\n * ```typescript\n * const app = new Act(registry, 100);\n * await app.do(\"increment\", { stream: \"counter1\", actor }, { by: 1 });\n * const snapshot = await app.load(Counter, \"counter1\");\n * await app.drain();\n * ```\n *\n * - Register event listeners with `.on(\"committed\", ...)` and `.on(\"acked\", ...)` to react to lifecycle events.\n * - Use `.query()` to analyze event streams for analytics or debugging.\n *\n * @template TSchemaReg SchemaRegister for state\n * @template TEvents Schemas for events\n * @template TActions Schemas for actions\n * @template TStateMap Map of state names to state schemas\n * @template TActor Actor type extending base Actor\n */\n/**\n * Default LRU cap for the subscribed-streams cache. Apps that mint many\n * dynamic targets (one per aggregate) should override via\n * {@link ActOptions.maxSubscribedStreams} based on expected concurrency.\n */\nexport const DEFAULT_MAX_SUBSCRIBED_STREAMS = 1000;\n\n/**\n * Default debounce window (ms) for `settle()` when neither the per-call\n * `SettleOptions.debounceMs` nor `ActOptions.settleDebounceMs` is set.\n * Coalesces commits in the same tick and small bursts; sub-perceptible\n * latency on the `\"settled\"` signal.\n */\nexport const DEFAULT_SETTLE_DEBOUNCE_MS = 10;\n\n// Re-export the autoclose config surface so operators can\n// `import { DEFAULT_AUTOCLOSE_CYCLE_MINUTES, resolveAutocloseConfig }\n// from \"@rotorsoft/act\"`. The implementation lives in\n// `internal/config.ts` (the single home for builder-facing config bags)\n// to keep this orchestrator file focused on the `Act` class.\nexport {\n type AutocloseConfig,\n type AutoclosePolicy,\n DEFAULT_AUTOCLOSE_CYCLE_MINUTES,\n DEFAULT_CLOSE_BATCH_SIZE,\n DEFAULT_CLOSE_YIELD_MS,\n resolveAutocloseConfig,\n} from \"./internal/index.js\";\n\n/**\n * Lifecycle events emitted by {@link Act}, mapped to their payload type.\n * Drives the typing of `emit` / `on` / `off` — the event-name argument\n * narrows its payload at the call site.\n *\n * The first parameter is kept (unused) for arity compatibility: `committed`\n * carries snapshots of whichever state each action targeted, so its honest\n * element type is `Snapshot<Schema, TEvents>` — the register map itself was\n * never the shape of any snapshot's state.\n */\nexport type ActLifecycleEvents<\n _TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n> = {\n committed: Snapshot<Schema, TEvents>[];\n acked: Lease[];\n blocked: BlockedLease[];\n settled: Drain<TEvents>;\n closed: CloseResult;\n /**\n * A **different process** committed an event to the same backing store.\n *\n * Fires only when the configured store implements\n * {@link Store.notify} and there is at least one registered reaction.\n * The orchestrator uses the same signal internally to wake `settle()`\n * — listeners get the raw payload for SSE fan-out, dashboards, and\n * audit logs.\n *\n * Local commits do *not* fire `notified` (use `committed` for those):\n * stores self-filter their own writes so this channel has a clean\n * cross-process semantic.\n */\n notified: StoreNotification;\n /**\n * A stream's sensitive-data payload was wiped via {@link Act.forget}.\n * Fires exactly once per successful `forget(stream)` call — idempotent\n * second calls (no PII left on the stream) return `eventCount: 0` and\n * do NOT re-emit. Apps that never call `forget()` never see this event.\n *\n * Listeners use it for the compliance side of GDPR / CCPA: audit log,\n * downstream cache busts, projection-side wipes that the framework\n * doesn't reach (e.g., search indexes, ETL caches). The framework's own\n * cache is invalidated by `forget()` itself before the event fires.\n */\n forgotten: { stream: string; at: Date; eventCount: number };\n /**\n * A store operation failed during the drain loop (ACT-984). Fires on\n * every failed drain cycle — typically a {@link StoreError} from a\n * degraded backend — carrying the orchestrator circuit breaker's state\n * after the failure (`open` means the drain loop has backed off and will\n * retry after the cooldown). Listen to alert on a degraded store; the\n * framework logs the same error regardless. Emitted only when a listener\n * is registered (Node's `EventEmitter` throws on an unhandled `\"error\"`).\n */\n error: { error: unknown; circuit: CircuitState };\n};\n\n/**\n * Options for {@link Act} construction (passed via {@link ActBuilder.build}).\n *\n * @property maxSubscribedStreams - Cap for the LRU set tracking already-\n * subscribed reaction streams. Default: {@link DEFAULT_MAX_SUBSCRIBED_STREAMS}.\n * @property settleDebounceMs - Debounce window (ms) used by `settle()` when\n * the caller doesn't pass `SettleOptions.debounceMs`. Tune this once per\n * Act instance instead of threading the value through every call site.\n * Default: {@link DEFAULT_SETTLE_DEBOUNCE_MS}.\n */\nexport type ActOptions<TLanes extends string = string> = {\n readonly maxSubscribedStreams?: number;\n readonly settleDebounceMs?: number;\n /**\n * Per-Act ports (ACT-501). When set, this Act runs against the\n * provided store + cache instead of the singletons — threaded via\n * AsyncLocalStorage so internals are unchanged. Both are required\n * together (a shared cache across distinct stores would collide on\n * stream keys). Omit for the singleton path.\n */\n readonly scoped?: Scoped;\n /**\n * Correlation-id generator for originating actions (ACT-404). When\n * omitted, Act uses {@link default_correlator}, which produces a\n * readable, time-monotonic-within-window, lowercase id of the form\n * `{state[:4]}-{action[:4]}-{ts}{rnd}` (18 chars).\n *\n * Reactions inherit `reactingTo.meta.correlation` so the chain stays\n * intact — the delegate is only consulted on originating commits and\n * for the close-the-books transaction.\n */\n readonly correlator?: Correlator;\n /** Restrict this process to a subset of declared lanes (ACT-1103). */\n readonly onlyLanes?: ReadonlyArray<TLanes>;\n /**\n * Subscribe to {@link Store.notify} on this instance (#803). Defaults\n * to `true`. Set `false` on instances that only commit and never\n * react — the subscriber-connection budget is the practical scaling\n * ceiling for the notify/listen pattern, and writer-only fleets\n * spend it for nothing when they subscribe to a channel they never\n * read. Commits still emit notifications (that's part of the\n * store's commit protocol); only the subscriber side is gated.\n */\n readonly listen?: boolean;\n /**\n * Run the local reaction pipeline on this instance (#803). Defaults\n * to `true`. Set `false` on writer-only or sidecar instances: drain\n * controllers' auto-cycle workers don't start, `correlate()` /\n * `drain()` / `settle()` become no-ops, and the notify handler\n * skips its drain-wakeup arm (but still emits the `notified`\n * lifecycle event so observability sidecars work).\n */\n readonly drain?: boolean;\n /**\n * Orchestrator circuit breaker for the drain loop (ACT-984). After\n * `failureThreshold` consecutive store failures the breaker opens and\n * the drain loop skips `claim()` for `cooldownMs` instead of hammering a\n * down backend, then allows a half-open trial. Out-of-range values throw\n * a `ZodError` at `act().build()`. Defaults: threshold 5, cooldown 30s.\n */\n readonly circuitBreaker?: CircuitBreakerOptions;\n /**\n * @deprecated Since #1175 this knob is accepted, validated, and\n * ignored. It paced the off-hours re-check of the pre-#1090 autoclose\n * sweep; the synthesized autoclose reaction now derives its re-check\n * directly from `autocloseWindow` — a tick landing outside the window\n * parks until the exact instant the window opens, so there is no\n * polling cadence to configure (and nothing minute-denominated on the\n * close surface). Still validated as an integer `[1, 1440]` so typos\n * keep failing loudly at `act().build()`. Will be removed in the next\n * major.\n */\n readonly autocloseCycleMinutes?: number;\n /**\n * @deprecated Dead since #1090 replaced the autoclose sweep with a\n * synthesized per-aggregate reaction — nothing pages the store in\n * batches anymore, so nothing reads this. Accepted and validated\n * (`[1, 1024]`) for compatibility; will be removed in the next major.\n */\n readonly closeBatchSize?: number;\n /**\n * @deprecated Dead since #1090 — the sweep that yielded between\n * successive `Store.truncate` calls no longer exists; closes are\n * staged per stream by the autoclose reaction. Accepted and validated\n * (`[0, 1000]`) for compatibility; will be removed in the next major.\n */\n readonly closeYieldMs?: number;\n /**\n * @deprecated Dead since #1090 — the sweep-side predicate try/catch\n * this flag steered no longer exists; a throwing policy predicate now\n * follows the reaction retry path (`blockOnError: false`, three\n * retries). Accepted for compatibility; will be removed in the next\n * major.\n */\n readonly closeOnError?: boolean;\n /**\n * Optional off-hours window restricting when autoclose evaluates. A\n * synthesized autoclose reaction that triggers outside the window\n * defers to the next instant the window opens — derived from the\n * window itself, no polling cadence. Hours are `[0, 23]` integers in\n * `timeZone` (IANA, default `\"UTC\"`, DST-correct); `start > end` is\n * an overnight window (e.g. `{ start: 22, end: 6 }`). Omit to\n * evaluate regardless of clock time.\n */\n readonly autocloseWindow?: {\n readonly start: number;\n readonly end: number;\n readonly timeZone?: string;\n };\n /**\n * Validate folded state against its declared Zod schema after every\n * reduction (ACT-1238). Off by default.\n *\n * When `true`, each time an event is folded into state — on the\n * command path (`do`), on `load`/replay, and inside projection-fold\n * projections — the merged full state is parsed against the owning\n * state's `state({ Name: schema })` schema. A reducer that produces\n * schema-violating state (the calculator divide-by-zero NaN class,\n * #1230) throws a {@link ValidationError} at the triggering event,\n * whose `target` names the state and the event (`<state>.<event>#<id>`)\n * — instead of the bad value propagating and surfacing hops later as a\n * confusing downstream error.\n *\n * This is a **debugging / CI aid, not a production guard**. Turn it on\n * in development and CI to catch total-reducer bugs at the source; the\n * framework already validates action inputs and emitted events, so the\n * reduced state is the one shape it otherwise trusts. The per-event\n * patch step is selected **once at `build()`** (the same way the\n * orchestrator picks bare vs trace-decorated store ops from the log\n * level): when `false` (the default) the fold loop is byte-identical to\n * a bare reduction — the validating patch step is never selected, so\n * there is no per-event cost, not even a branch.\n */\n readonly validateFoldedState?: boolean;\n};\n\n/** Reject `onlyLanes` entries that reference undeclared lanes. */\nfunction validate_only_lanes(\n options: ActOptions,\n lanes: ReadonlyArray<LaneConfig>\n): void {\n if (!options.onlyLanes || options.onlyLanes.length === 0) return;\n const declared = new Set<string>([\"default\", ...lanes.map((l) => l.name)]);\n const unknown = options.onlyLanes.filter((l) => !declared.has(l));\n if (unknown.length > 0)\n throw new Error(\n `ActOptions.onlyLanes references undeclared lane(s): ${unknown\n .map((l) => `\"${l}\"`)\n .join(\", \")}`\n );\n}\n\nexport class Act<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n TStateMap extends Record<string, Schema> = Record<string, never>,\n TActor extends Actor = Actor,\n> implements IAct<TEvents, TActions, TActor, TSchemaReg>\n{\n private _emitter = new EventEmitter();\n /** ACT-984: orchestrator-owned circuit breaker shared by all drain lanes. */\n private readonly _breaker: CircuitBreaker;\n /** #803: gate the `Store.notify` subscription side. */\n private readonly _listen: boolean;\n /** #803: gate the local reaction pipeline (drain controllers, settle, correlate). */\n private readonly _drain: boolean;\n /** Event names with at least one registered reaction (computed at build time) */\n private readonly _reactive_events: ReadonlySet<string>;\n /** One DrainController per active lane, keyed by lane name. */\n private readonly _drain_controllers: Map<\n string,\n DrainController<TEvents, TActions, TSchemaReg>\n >;\n /** Correlation state machine: lazy init, dynamic-resolver scan, periodic worker. */\n private readonly _correlate: CorrelateCycle<TSchemaReg, TEvents, TActions>;\n /** Debounced correlate→drain catch-up loop. */\n private readonly _settle: SettleLoop<TEvents>;\n /**\n * Disposer for the cross-process notify subscription, set up eagerly\n * during construction. Held as a promise because the subscription\n * itself may be async (the PG adapter checks out a dedicated client\n * and runs `LISTEN` before resolving). Resolves to `undefined` when\n * the store doesn't implement `notify` or there are no registered\n * reactions.\n *\n * **Contract:** the configured store must be injected via\n * {@link store}`(adapter)` *before* calling `act()...build()`. The\n * orchestrator wires notify against whatever store is current at\n * construction time — late injection after build is unsupported.\n */\n private readonly _notify_disposer: Promise<\n (() => void | Promise<void>) | undefined\n >;\n /** Public registry — kept as-is per the no-prefix-on-public convention. */\n public readonly registry: Registry<\n TSchemaReg,\n TEvents,\n TActions,\n keyof TStateMap & string\n >;\n /** Map of state name → state definition; populated by the builder. */\n private readonly _states: Map<string, State<any, any, any>>;\n /**\n * Emit a lifecycle event. The payload type is inferred from the event name\n * via {@link ActLifecycleEvents}.\n *\n * **Every listener is contained individually.** Lifecycle listeners are\n * observers — `observability.md` promises that a throwing one is \"contained,\n * not fatal\" — and containment belongs here rather than at each call site,\n * for two reasons the previous arrangement got wrong (#1437):\n *\n * - Wrapping the *emit* rather than each *listener* still let the first\n * thrower abort the rest: `EventEmitter.emit` stops dispatching on the\n * first exception, so a second `app.on(\"acked\", …)` never ran. The\n * documented \"the remaining sinks still fire\" was false whenever an event\n * had more than one listener. Same lesson as #1423, where guarding the\n * loop instead of each callback left every later SSE subscriber unserved.\n * - Only *some* call sites wrapped at all. The drain contained `acked` and\n * `blocked`; `committed`, `forgotten` and `close()`'s `closed` did not, so\n * a throwing listener rejected `do()`, `forget()` and `close()` **after**\n * their durable work had already landed. A caller retrying a \"failed\"\n * `do()` writes the event twice, since the framework has no dedup by\n * design.\n *\n * Containing here makes it a property of emitting, so a new lifecycle event\n * cannot reintroduce the gap by omission.\n *\n * Uses `rawListeners` so `once` wrappers still de-register themselves, and\n * returns \"had listeners\" to preserve the `EventEmitter.emit` contract.\n */\n emit<E extends keyof ActLifecycleEvents<TSchemaReg, TEvents, TActions>>(\n event: E,\n args: ActLifecycleEvents<TSchemaReg, TEvents, TActions>[E]\n ): boolean {\n const listeners = this._emitter.rawListeners(event as string);\n for (const listener of listeners) {\n try {\n listener(args);\n } catch (error) {\n this._logger.error(error, `${String(event)} listener threw`);\n }\n }\n return listeners.length > 0;\n }\n\n /**\n * The single store-failure handler: log it, then emit the `error`\n * lifecycle event. Wired into the circuit breaker's `on_error`, so it\n * runs on every `failed()` — drain / settle / autoclose just call\n * `breaker.failed(now, error)` and never log or emit themselves.\n *\n * The emit is guarded against Node's `EventEmitter` contract that an\n * unhandled `\"error\"` emission is rethrown (which would crash the process\n * from inside the drain catch); logging is unconditional so failures are\n * never silent.\n */\n private _emit_error(error: unknown, circuit: CircuitState): void {\n this._logger.error(error);\n if (this._emitter.listenerCount(\"error\") > 0)\n this.emit(\"error\", { error, circuit });\n }\n\n /**\n * Register a listener for a lifecycle event. The listener receives the\n * event-specific payload.\n */\n on<E extends keyof ActLifecycleEvents<TSchemaReg, TEvents, TActions>>(\n event: E,\n listener: (\n args: ActLifecycleEvents<TSchemaReg, TEvents, TActions>[E]\n ) => void\n ): this {\n this._emitter.on(event, listener);\n return this;\n }\n\n /**\n * Remove a previously registered lifecycle listener.\n */\n off<E extends keyof ActLifecycleEvents<TSchemaReg, TEvents, TActions>>(\n event: E,\n listener: (\n args: ActLifecycleEvents<TSchemaReg, TEvents, TActions>[E]\n ) => void\n ): this {\n this._emitter.off(event, listener);\n return this;\n }\n\n /** Batch handlers for static-target projections (target → handler) */\n private readonly _batch_handlers: Map<string, BatchHandler<TEvents>>;\n /** Event-sourcing handlers, optionally wrapped with trace decorators */\n private readonly _es: EsOps;\n /** Correlate/drain pipeline ops, optionally wrapped with trace decorators */\n private readonly _cd: DrainOps<TEvents>;\n /**\n * Event-name → owning state, computed at build time. The duplicate-event\n * guard in merge.ts ensures one event name maps to at most one state, so\n * this lookup is unambiguous. Used by `close()` to pick the right reducer\n * set when seeding a `restart` snapshot in multi-state apps.\n */\n private readonly _event_to_state: ReadonlyMap<string, State<any, any, any>>;\n /**\n * Event-name → lane fan-in for selective arming (ACT-1103). Built by\n * `classify_registry` once per build. `\"all\"` means at least one of\n * the event's reactions is a dynamic resolver (lane opaque until\n * runtime); a `Set<string>` lists the static lanes only that event's\n * reactions target.\n */\n private readonly _event_to_lanes: ReadonlyMap<string, EventLaneSet>;\n /**\n * Audit dependency bag (#723). Built once at construction; held as\n * an immutable snapshot of the registry state the audit module\n * needs. Lives in `internal/audit.ts` — this orchestrator never\n * carries audit logic, only the deps + a one-liner that hands them\n * over.\n */\n private readonly _audit_deps: AuditDeps;\n /** Logger resolved at construction time (after user port configuration) */\n private readonly _logger: Logger = log();\n /** Wraps a public-method body so internal `store()`/`cache()` resolve to the\n * per-Act ports (ACT-501). No-op when the Act is unscoped — so the singleton\n * path keeps reading fresh `store()`/`cache()` per call, which matters for\n * tests that dispose and re-seed mid-suite. */\n private readonly _scoped: <T>(fn: () => Promise<T>) => Promise<T>;\n\n /**\n * Correlation-id generator for originating actions. Bound at\n * construction from `options.correlator ?? default_correlator`. The\n * `do()` path passes this into the `_es.action` closure; close-cycle\n * uses it via {@link close_correlation}.\n */\n private readonly _correlator: Correlator;\n /** Pre-bound IAct methods reused across drain cycles. Only `do` varies per\n * payload (it captures the triggering event for reactingTo auto-inject). */\n private readonly _bound_do = this.do.bind(this);\n private readonly _bound_load = this.load.bind(this);\n private readonly _bound_query = this.query.bind(this);\n private readonly _bound_query_array = this.query_array.bind(this);\n private readonly _bound_forget = this.forget.bind(this);\n /** Reaction dispatchers built once and handed to run_drain_cycle each cycle. */\n private readonly _handle: Handle<TEvents>;\n private readonly _handle_batch: HandleBatch<TEvents>;\n /** Declared drain lanes (ACT-1103). */\n private readonly _lanes: ReadonlyArray<LaneConfig>;\n\n /**\n * Per-stream close serialization tails (#1222). Chains each stream's\n * windowed-close work behind the previous one so a manual\n * `app.close([{stream, before}])` and an autoclose windowed close for\n * the same stream never run their guard-free prune concurrently — the\n * manual path bypasses the `__autoclose__:X` drain lease that would\n * otherwise exclude them, so without this both closers archive the\n * same prefix. Process-local: both racers run on the same Act\n * instance. Entries are dropped once their tail resolves so the map\n * doesn't grow with distinct stream names.\n */\n private readonly _close_locks = new Map<string, Promise<unknown>>();\n\n /**\n * Run `work` under the per-stream close lock (#1222). Serializes\n * windowed-close critical sections for the same stream while letting\n * different streams proceed in parallel.\n */\n private _with_close_lock<T>(\n stream: string,\n work: () => Promise<T>\n ): Promise<T> {\n const prev = this._close_locks.get(stream) ?? Promise.resolve();\n // Chain after the previous holder regardless of how it settled — a\n // failed close must not wedge the stream's lock forever. The next\n // waiter chains off `next` (the work), so its start is gated on this\n // work completing.\n const next = prev.then(work, work);\n this._close_locks.set(stream, next);\n // Drop the tail once it settles, but only if it's still the current\n // one — a later waiter that already replaced it owns the entry now.\n const cleanup = () => {\n if (this._close_locks.get(stream) === next)\n this._close_locks.delete(stream);\n };\n next.then(cleanup, cleanup);\n return next;\n }\n\n /** Drain lanes declared via `.withLane(...)`. Implicit default not included. */\n get lanes(): ReadonlyArray<LaneConfig> {\n return this._lanes;\n }\n\n /**\n * Create a new Act orchestrator. Prefer the {@link act} builder over\n * direct construction — `act()...build()` wires the registry, merges\n * partial states, and collects batch handlers from registered slices\n * and projections in one pass.\n *\n * @param registry Schemas for every event and action across registered states\n * @param states Merged map of state name → state definition\n * @param batch_handlers Static-target projection batch handlers (target → handler)\n * @param options Tuning knobs — see {@link ActOptions}\n * @param lanes Declared drain lanes (ACT-1103). The builder collects\n * these from `.withLane(...)` calls. Slice 1 records them on the\n * instance; later slices fan out one `DrainController` per lane.\n * @param patch_fn The per-event patch step selected once by the builder\n * from `ActOptions.validateFoldedState` (ACT-1238) — `bare_patch` by\n * default, `validating_patch` when the flag is on. The builder uses\n * the same value for its projection-fold handlers, so there is a\n * single selection site. Defaults to `bare_patch` for direct\n * construction.\n */\n constructor(\n registry: Registry<TSchemaReg, TEvents, TActions, keyof TStateMap & string>,\n states: Map<string, State<any, any, any>> = new Map(),\n batch_handlers: Map<string, BatchHandler<any>> = new Map(),\n options: ActOptions = {},\n lanes: ReadonlyArray<LaneConfig> = [],\n patch_fn: PatchFn = bare_patch\n ) {\n this.registry = registry;\n this._states = states;\n this._batch_handlers = batch_handlers;\n this._lanes = lanes;\n validate_only_lanes(options, lanes);\n this._scoped = options.scoped\n ? (fn) => scoped.run(options.scoped!, fn)\n : (fn) => fn();\n this._correlator = options.correlator ?? default_correlator;\n this._es = build_es(this._logger, this._correlator, patch_fn);\n this._cd = build_drain<TEvents>(this._logger);\n // Reaction-level PII wrapping happens at build time inside `act-builder`:\n // reactions registered against an event with `sensitive(...)` fields get\n // a stripping handler closure; reactions against non-PII events keep\n // their original handler reference. So the dispatcher is PII-unaware.\n this._handle = build_handle<TEvents, TActions, TActor>({\n logger: this._logger,\n bound_do: this._bound_do,\n bound_load: this._bound_load,\n bound_query: this._bound_query,\n bound_query_array: this._bound_query_array,\n bound_forget: this._bound_forget,\n });\n this._handle_batch = build_handle_batch<TEvents>(this._logger);\n\n // The registry arrives complete and frozen from the builder — the\n // autoclose reactions were synthesized there, so classification sees\n // the finished shape and nothing here mutates it.\n const classification = classify_registry(this.registry, this._states);\n this._reactive_events = classification.reactive_events;\n this._event_to_state = classification.event_to_state;\n this._event_to_lanes = classification.event_to_lanes;\n this._listen = options.listen !== false;\n this._drain = options.drain !== false;\n\n // Composition sequence — each step builds one runtime subsystem from\n // the pieces above. Order matters: controllers read the breaker, the\n // audit bag reads the finalized controller set, settle reads the\n // correlate cycle.\n this._breaker = this._build_breaker(options);\n this._drain_controllers = this._build_drain_controllers(options, lanes);\n this._advise_orphaned_lanes(options, lanes);\n this._audit_deps = this._build_audit_deps();\n this._correlate = this._build_correlate(options, classification);\n this._settle = this._build_settle(options);\n\n // Auto-wire cross-process notify when the store supports it. Bound at\n // construction time — late `store(adapter)` injection after build won't\n // take effect. Scoped Acts bind against their own store.\n this._notify_disposer = this._wire_notify(options.scoped?.store ?? store());\n\n // Registered weakly (#1441). A plain `dispose(() => this.shutdown())`\n // closure captures `this` in a module-level array that is never emptied,\n // so every Act ever built — with its registry, drain controllers, and for\n // a scoped Act its own store and cache, connection pools included —\n // survives for the process lifetime. Apps that mint short-lived Acts (one\n // per tenant, per request, per test) leak one apiece. Holding the\n // reference weakly keeps process-wide `dispose()()` working for a live\n // Act while letting an unreachable one be collected, shut down or not.\n register_weak_disposer(new WeakRef(this), (self) => self.shutdown());\n }\n\n /**\n * Circuit breaker shared by every store-polling loop (drain, the settle\n * correlate, autoclose). Validates the knobs eagerly so out-of-range\n * values throw at build time, not on the first cycle tick.\n */\n private _build_breaker(options: ActOptions): CircuitBreaker {\n return new CircuitBreaker(\n resolveCircuitBreakerConfig(options.circuitBreaker),\n {\n on_error: (error, circuit) => this._emit_error(error, circuit),\n // Re-probe the store when the cooldown elapses, so recovery is\n // automatic even on the default lane (which has no periodic poller).\n // The wake fires `settle()`, which (in half-open) runs a real store\n // probe: for a dynamic-resolver app the probe is settle's correlate\n // (a store scan); for a static-reaction app correlate is a no-op that\n // records no health, so the probe is settle's DRAIN claim — either\n // way one success closes the breaker and every loop resumes, a\n // failure re-opens it and reschedules the wake. Settle does NOT close\n // the breaker off a no-op correlate (#1329) — only a real store op\n // (correlate scan or drain claim) records `passed()`.\n on_retry: () => {\n this.settle({ debounceMs: 0 });\n },\n }\n );\n }\n\n /**\n * One DrainController per active lane. The implicit \"default\" lane is\n * always present unless onlyLanes excludes it. Each controller filters\n * its claim() by its lane name; the legacy single-controller path is the\n * active set === { \"default\" } case with `lane: undefined` deps so\n * claim() doesn't filter (preserves the single-lane SQL planner shape\n * for apps that never call withLane).\n */\n private _build_drain_controllers(\n options: ActOptions,\n lanes: ReadonlyArray<LaneConfig>\n ): Map<string, DrainController<TEvents, TActions, TSchemaReg>> {\n const all_lanes = [\"default\", ...lanes.map((l) => l.name)];\n const only_set =\n options.onlyLanes && options.onlyLanes.length > 0\n ? new Set<string>(options.onlyLanes as readonly string[])\n : undefined;\n const active_lanes = only_set\n ? all_lanes.filter((n) => only_set.has(n))\n : all_lanes;\n const single_default_lane =\n active_lanes.length === 1 && active_lanes[0] === \"default\";\n const controllers = new Map<\n string,\n DrainController<TEvents, TActions, TSchemaReg>\n >();\n for (const name of active_lanes) {\n const cfg = lanes.find((l) => l.name === name);\n const controller = new DrainController({\n logger: this._logger,\n ops: this._cd,\n registry: this.registry,\n batch_handlers: this._batch_handlers,\n handle: this._handle,\n handle_batch: this._handle_batch,\n on_acked: (acked) => this.emit(\"acked\", acked),\n on_blocked: (blocked) => this.emit(\"blocked\", blocked),\n // Reaction-requested close. Runs the same close machinery as\n // `app.close` (tombstone guard + archive + atomic truncate) for the\n // targets a handler signalled via `CloseSignal`. No `correlate()`\n // here — the drain that produced these targets has already\n // correlated.\n on_close: async (targets) => {\n const close_actor = { id: \"$close\", name: \"close\" };\n const result = await run_close_cycle(targets, {\n reactive_events_size: this._reactive_events.size,\n event_to_state: this._event_to_state,\n load: this._es.load,\n tombstone: this._es.tombstone,\n logger: this._logger,\n correlation: close_correlation(this._correlator, close_actor),\n with_stream_lock: (stream, work) =>\n this._with_close_lock(stream, work),\n });\n this._forget_closed_subscriptions(result);\n // The close machinery above is deliberately NOT wrapped, so a\n // real StoreError reaches the breaker (#1388). The emit needs no\n // guard here: `Act.emit` contains each listener (#1437).\n this.emit(\"closed\", result);\n },\n breaker: this._breaker,\n // Re-scope the per-lane worker's auto-start ticks so their drain\n // resolves the scoped ports, not the singleton (#1191).\n run_scoped: this._scoped,\n // Pass lane only when a true per-lane controller is active.\n // The all-lanes (single default) case keeps lane=undefined so\n // adapter SQL collapses to the single-lane shape.\n lane: single_default_lane ? undefined : name,\n defaults: cfg && {\n streamLimit: cfg.streamLimit,\n leaseMillis: cfg.leaseMillis,\n },\n });\n // Auto-start a per-lane worker when the operator declared a\n // cycleMs — the intent of `withLane({cycleMs: 100})` is \"drive\n // this lane every 100 ms,\" independent of the Act-level settle\n // loop. unref()'d so the timer doesn't keep the process alive.\n // Writer-only instances (`drain: false`) construct the controller\n // but never run reactions locally, so the auto-start is skipped.\n if (cfg?.cycleMs !== undefined && options.drain !== false)\n controller.start(cfg.cycleMs);\n controllers.set(name, controller);\n }\n return controllers;\n }\n\n /**\n * Orphaned-lane startup advisory (#1220). When `onlyLanes` is set, this\n * instance builds a controller only for its slice of the declared lane\n * universe — every OTHER declared lane's stream is persisted (correlate\n * subscribes all static targets regardless of `onlyLanes`) but never\n * claimed here. If no peer worker deploys with those lanes in ITS\n * `onlyLanes`, their reactions accumulate forever, silently. A single\n * process can't verify the cluster invariant `∪ onlyLanes ⊇ declared\n * lanes`, so we surface the per-instance signal — \"these declared lanes\n * have no controller here\" — the same way the deprecated-event advisory\n * surfaces legacy events. No advisory when `onlyLanes` is unset (every\n * lane gets a controller) or covers every declared lane.\n */\n private _advise_orphaned_lanes(\n options: ActOptions,\n lanes: ReadonlyArray<LaneConfig>\n ): void {\n if (!options.onlyLanes || options.onlyLanes.length === 0) return;\n const active = new Set(this._drain_controllers.keys());\n const orphaned = [\"default\", ...lanes.map((l) => l.name)].filter(\n (name) => !active.has(name)\n );\n if (orphaned.length === 0) return;\n const list = orphaned.map((name) => `\"${name}\"`).join(\", \");\n this._logger.info(\n `Act declared ${orphaned.length} orphaned lane(s) on this instance: ${list}. ` +\n `onlyLanes excludes them, so no DrainController claims their streams here — ` +\n `their reactions accumulate un-drained unless a peer worker deploys with these ` +\n `lanes in its onlyLanes. Ensure the cluster invariant holds: the union of every ` +\n `worker's onlyLanes must cover every declared lane. ` +\n `See docs/docs/guides/production-checklist.md § Sizing lanes.`\n );\n }\n\n /**\n * Audit deps bag. Snapshotted after registry classification and\n * drain-controller build so the audit module sees the finalized lane\n * set. Held as an immutable bag — the orchestrator never carries audit\n * logic itself, only this typed contract.\n */\n private _build_audit_deps(): AuditDeps {\n return {\n store,\n logger: this._logger,\n event_to_state: this._event_to_state,\n states: this._states,\n // The DECLARED lane universe — the implicit \"default\" plus every\n // `.withLane(...)` name — NOT `_drain_controllers.keys()` (#1224).\n // An `onlyLanes`-filtered instance builds a controller only for its\n // slice of lanes, so keying off the active controller set would flag\n // a stream correctly assigned to an excluded-but-declared lane (one\n // another worker drains) as `unknown-lane`. The audit reports what's\n // structurally routable across the cluster, not what this process runs.\n declared_lanes: new Set([\"default\", ...this._lanes.map((l) => l.name)]),\n routed_events: new Set(this._event_to_lanes.keys()),\n };\n }\n\n /**\n * Correlate cycle over the classified registry. The cold-start callback\n * arms every controller — historical events may need processing —\n * except on writer-only instances (`drain: false`).\n */\n private _build_correlate(\n options: ActOptions,\n classification: ReturnType<\n typeof classify_registry<TSchemaReg, TEvents, TActions>\n >\n ): CorrelateCycle<TSchemaReg, TEvents, TActions> {\n return new CorrelateCycle({\n registry: this.registry,\n static_targets: classification.static_targets,\n has_dynamic_resolvers: classification.has_dynamic_resolvers,\n cd: this._cd,\n max_subscribed_streams:\n options.maxSubscribedStreams ?? DEFAULT_MAX_SUBSCRIBED_STREAMS,\n on_init: () => {\n if (this._drain && this._reactive_events.size > 0) this._arm_all();\n },\n // Re-scope the background `start_correlations` timer so its\n // correlate resolves the scoped ports, not the singleton (#1191).\n run_scoped: this._scoped,\n // Cold-start defer re-seed (#1221). Skipped on writer-only instances\n // (`drain: false`) — they run no local controllers to re-arm.\n on_init_async: this._drain\n ? () => this._seed_persisted_defers()\n : undefined,\n });\n }\n\n /**\n * Re-seed every active lane controller's process-local defer timer from\n * the store's persisted `deferred_at` (#1221). Runs once at cold start,\n * inside `CorrelateCycle.init`, after static targets are subscribed.\n *\n * The defer timer is worker memory: empty after a restart. A stream\n * deferred to a future due-time (the classic case: an idle autoclose\n * aggregate that deferred its terminal close) is durable in the store but\n * has nothing in memory to re-arm the drain — the controller disarms on\n * the first empty claim and, since the aggregate is idle, no commit ever\n * re-arms it. Reading the persisted schedule and seeding the owning lane's\n * timer restores the wake, so the close fires at the due-time.\n *\n * Streams whose lane has no controller on this instance (excluded by\n * `onlyLanes`) are skipped — a peer worker owns that lane's timer.\n */\n private async _seed_persisted_defers(): Promise<void> {\n const now = Date.now();\n // Paged — `query_streams` defaults to 100, and a stream sorting past\n // the first page would never get its timer re-armed. The failing case\n // is exactly the one described above: an idle aggregate no commit\n // ever re-arms.\n await walk_streams(store(), (pos) => {\n // Only future defers matter — a past-due schedule is claimable\n // already, so the ordinary armed drain picks it up.\n if (pos.deferred_at === undefined || pos.deferred_at <= now) return;\n // Route to the controller that owns the stream's lane. A missing\n // controller means the lane is excluded on this instance (onlyLanes) —\n // skip it, a peer worker owns that timer. The default lane's\n // controller is keyed \"default\" and matches an undefined stored lane.\n const controller = this._drain_controllers.get(pos.lane ?? \"default\");\n controller?.seed_defer(pos.stream, pos.deferred_at);\n });\n }\n\n /** Settle loop driving correlate + drain to quiescence. */\n private _build_settle(options: ActOptions): SettleLoop<TEvents> {\n return new SettleLoop<TEvents>(\n {\n // Scope the init like every other store-touching path — a bare\n // `this._correlate.init()` runs `store().subscribe(...)` against\n // the singleton for a scoped Act, so static targets never land on\n // the scoped store and `_initialized` then blocks a retry (#1191).\n init: () => this._scoped(() => this._correlate.init()),\n checkpoint: () => this._correlate.checkpoint,\n correlate: (q) => this.correlate(q),\n drain: (o) => this.drain(o),\n on_settled: (drain) => this.emit(\"settled\", drain),\n breaker: this._breaker,\n // Static-reaction apps' correlate is a no-op (no store call), so a\n // settle pass carries no store-health signal — don't let it record a\n // breaker success (#1329).\n correlate_probes_store: this._correlate.has_dynamic_resolvers,\n },\n options.settleDebounceMs ?? DEFAULT_SETTLE_DEBOUNCE_MS\n );\n }\n\n /** True after the first `shutdown()` call. Guards idempotency. */\n private _shutdown_promise: Promise<void> | undefined;\n\n /**\n * Per-instance teardown: remove lifecycle listeners, stop the\n * correlation worker, cancel any pending settle cycle, and tear\n * down the cross-process notify subscription.\n *\n * Idempotent — repeated calls return the same promise. Registered\n * automatically with the global `dispose()` registry at construction,\n * so process-wide `dispose()()` covers it; test helpers (or operators\n * that mint short-lived Acts) call it explicitly for prompt cleanup.\n */\n shutdown(): Promise<void> {\n if (!this._shutdown_promise) {\n this._shutdown_promise = (async () => {\n this._emitter.removeAllListeners();\n this.stop_correlations();\n this.stop_settling();\n this._breaker.stop();\n for (const c of this._drain_controllers.values()) c.stop();\n // `_wire_notify` swallows subscription errors and resolves to\n // `undefined`, so this promise never rejects.\n const disposer = await this._notify_disposer;\n if (disposer) await disposer();\n })();\n }\n return this._shutdown_promise;\n }\n\n /**\n * Subscribe to {@link Store.notify} when both the store and the\n * registry support it. Returns the disposer (or `undefined` when no\n * subscription was made). Errors during subscription are logged but\n * never thrown — `notify` is a hint, not a contract.\n */\n private async _wire_notify(\n s: Store\n ): Promise<(() => void | Promise<void>) | undefined> {\n if (this._reactive_events.size === 0) return undefined;\n if (!s.notify) return undefined;\n // #803: writer-only / single-instance deployments opt out of the\n // subscriber-connection cost. Commits still notify (that's the\n // store's commit protocol); only the subscriber side is gated.\n if (!this._listen) return undefined;\n try {\n return await s.notify((notification) => {\n // Generic concerns (lifecycle emit, drain wakeup, listener\n // error containment) live here so adapters only have to\n // handle their own wire format. Errors in user-registered\n // `notified` listeners or in our own bookkeeping are logged\n // and swallowed — the store's listener stays alive.\n try {\n this.emit(\"notified\", notification);\n // Wake once per commit when at least one event has a local\n // reaction. Avoids spurious wake-ups for remote commits\n // belonging to bounded contexts this process doesn't react to.\n // ACT-1103: selective arming via the shared helper — only the\n // lanes whose reactions match the notified events.\n // #803: the sidecar pattern (listen: true, drain: false)\n // wants the `notified` lifecycle event for observability\n // without engaging the local reaction pipeline.\n if (this._drain) {\n const armed = this._arm_for_event_names(\n notification.events.map((e) => e.name)\n );\n if (armed) this._settle.schedule({ debounceMs: 0 });\n }\n } catch (err) {\n this._logger.error(err, \"notified handler threw\");\n }\n });\n } catch (err) {\n this._logger.error(err, \"Store.notify subscription failed\");\n return undefined;\n }\n }\n\n /**\n * Executes an action on a state instance, committing resulting events.\n *\n * This is the primary method for modifying state. It:\n * 1. Validates the action payload against the schema\n * 2. Loads the current state snapshot\n * 3. Checks invariants (business rules)\n * 4. Executes the action handler to generate events\n * 5. Applies events to create new state\n * 6. Commits events to the store with optimistic concurrency control\n *\n * @template TKey - Action name from registered actions\n * @param action - The name of the action to execute\n * @param target - Target specification with stream ID and actor context\n * @param payload - Action payload matching the action's schema\n * @param options - Per-call dispatch options ({@link DoOptions}) —\n * `reactingTo` to thread correlation, `correlator` to override the\n * framework or orchestrator-level correlator for this call only.\n * @returns Array of snapshots for all affected states (usually one)\n *\n * @throws {ValidationError} If payload doesn't match action schema\n * @throws {InvariantError} If business rules are violated\n * @throws {ConcurrencyError} If another process modified the stream\n *\n * @example Basic action execution\n * ```typescript\n * const snapshots = await app.do(\n * \"increment\",\n * {\n * stream: \"counter-1\",\n * actor: { id: \"user1\", name: \"Alice\" }\n * },\n * { by: 5 }\n * );\n *\n * console.log(snapshots[0].state.count); // Current count after increment\n * ```\n *\n * @example With error handling\n * ```typescript\n * try {\n * await app.do(\n * \"withdraw\",\n * { stream: \"account-123\", actor: { id: \"user1\", name: \"Alice\" } },\n * { amount: 1000 }\n * );\n * } catch (error) {\n * if (error instanceof InvariantError) {\n * console.error(\"Business rule violated:\", error.description);\n * } else if (error instanceof ConcurrencyError) {\n * console.error(\"Concurrent modification detected, retry...\");\n * } else if (error instanceof ValidationError) {\n * console.error(\"Invalid payload:\", error.details);\n * }\n * }\n * ```\n *\n * @example Reaction triggering another action (reactingTo auto-injected)\n * ```typescript\n * const app = act()\n * .withState(Order)\n * .withState(Inventory)\n * .on(\"OrderPlaced\")\n * .do(async function reduceInventory(event, _stream, app) {\n * // Inside reaction handlers, reactingTo is auto-injected when omitted.\n * // The triggering event is used by default, maintaining the correlation chain.\n * await app.do(\n * \"reduceStock\",\n * { stream: \"inventory-1\", actor: { id: \"sys\", name: \"system\" } },\n * { amount: event.data.items.length }\n * );\n * // To use a different correlation, pass reactingTo explicitly:\n * // await app.do(\"reduceStock\", target, payload, { reactingTo: customEvent });\n * })\n * .to(\"inventory-1\")\n * .build();\n * ```\n *\n * @see {@link Target} for target structure\n * @see {@link Snapshot} for return value structure\n * @see {@link ValidationError}, {@link InvariantError}, {@link ConcurrencyError}\n */\n async do<TKey extends keyof TActions>(\n action: TKey,\n target: Target<TActor>,\n payload: Readonly<TActions[TKey]>,\n options?: DoOptions<TEvents>\n ) {\n return this._scoped(async () => {\n const snapshots = await this._es.action(\n this.registry.actions[action],\n action,\n target,\n payload,\n options\n );\n // Arm the drain when any committed event has reactions (ACT-1103:\n // arm only the lanes whose reactions match — events whose reactions\n // are all statically lane-resolved arm a subset; events with at\n // least one dynamic resolver fall back to _arm_all via the \"all\"\n // sentinel).\n if (this._reactive_events.size > 0)\n // Snapshots produced by `action()` always carry their committed\n // event — the optional `event?` on the type is for load()\n // snapshots, which don't reach this path.\n this._arm_for_event_names(\n snapshots.map((s) => (s.event as { name: string }).name)\n );\n this.emit(\"committed\", snapshots);\n return snapshots;\n });\n }\n\n /**\n * Loads the current state snapshot for a specific stream.\n *\n * Reconstructs the current state by replaying events from the event store.\n * Uses snapshots when available to optimize loading performance.\n *\n * Accepts either a State definition object or a state name string. When\n * using a string, the merged state (from partial states registered via\n * `.withState()`) is resolved by name.\n *\n * @template TNewState - State schema type\n * @template TNewEvents - Event schemas type\n * @template TNewActions - Action schemas type\n * @param state - The state definition or state name to load\n * @param stream - The stream ID (state instance identifier)\n * @param callback - Optional callback invoked with the loaded snapshot\n * @returns The current state snapshot for the stream\n *\n * @example Load by state definition\n * ```typescript\n * const snapshot = await app.load(Counter, \"counter-1\");\n * console.log(snapshot.state.count); // Current count\n * console.log(snapshot.patches); // Events since last snapshot\n * ```\n *\n * @example Load by state name (useful with partial states)\n * ```typescript\n * const snapshot = await app.load(\"Ticket\", \"ticket-123\");\n * console.log(snapshot.state.title); // Merged state from all partials\n * ```\n *\n * @example Load multiple states\n * ```typescript\n * const [user, account] = await Promise.all([\n * app.load(User, \"user-123\"),\n * app.load(BankAccount, \"account-456\")\n * ]);\n * ```\n *\n * @see {@link Snapshot} for snapshot structure\n */\n // Anonymous load (bare stream) — sensitive fields come back as REDACTED.\n async load<\n TNewState extends Schema,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n >(\n state: State<TNewState, TNewEvents, TNewActions>,\n stream: string,\n callback?: (snapshot: Snapshot<TNewState, TNewEvents>) => void,\n asOf?: AsOf\n ): Promise<Snapshot<TNewState, TNewEvents>>;\n async load<TKey extends keyof TStateMap & string>(\n name: TKey,\n stream: string,\n callback?: (snapshot: Snapshot<TStateMap[TKey], TEvents>) => void,\n asOf?: AsOf\n ): Promise<Snapshot<TStateMap[TKey], TEvents>>;\n // Auth-aware load — runs `.discloses(predicate)` against the supplied actor.\n async load<\n TNewState extends Schema,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n >(\n state: State<TNewState, TNewEvents, TNewActions>,\n target: LoadTarget<TActor>,\n callback?: (snapshot: Snapshot<TNewState, TNewEvents>) => void\n ): Promise<Snapshot<TNewState, TNewEvents>>;\n async load<TKey extends keyof TStateMap & string>(\n name: TKey,\n target: LoadTarget<TActor>,\n callback?: (snapshot: Snapshot<TStateMap[TKey], TEvents>) => void\n ): Promise<Snapshot<TStateMap[TKey], TEvents>>;\n async load<TNewState extends Schema>(\n stateOrName: State<TNewState, any, any> | string,\n streamOrTarget: string | LoadTarget<TActor>,\n callback?: (snapshot: Snapshot<any, any>) => void,\n asOf?: AsOf\n ): Promise<Snapshot<any, any>> {\n return this._scoped(async () => {\n let merged: State<any, any, any>;\n if (typeof stateOrName === \"string\") {\n const found = this._states.get(stateOrName);\n if (!found) throw new Error(`State \"${stateOrName}\" not found`);\n merged = found;\n } else {\n merged = this._states.get(stateOrName.name) || stateOrName;\n }\n // Normalize the two surfaces: bare-stream (default-deny — actor\n // undefined → REDACTED on the discloses check) vs LoadTarget\n // (auth-aware — actor flows into `.discloses(predicate)`).\n const target: LoadTarget<Actor> =\n typeof streamOrTarget === \"string\"\n ? {\n stream: streamOrTarget,\n actor: undefined as unknown as Actor,\n asOf,\n }\n : streamOrTarget;\n return await this._es.load(merged, target, callback);\n });\n }\n\n /**\n * Queries the event store for events matching a filter.\n *\n * Use this for analyzing event streams, generating reports, or debugging.\n * The callback is invoked for each matching event, and the method returns\n * summary information (first event, last event, total count).\n *\n * For small result sets, consider using {@link query_array} instead.\n *\n * @param query - Filter criteria — see {@link Query} for available fields\n * (`stream`, `name`, `after`, `before`, `created_after`, `created_before`,\n * `limit`, `with_snaps`, `stream_exact`)\n * @param callback - Optional callback invoked for each matching event\n * @returns Object with first event, last event, and total count\n *\n * @example Query all events for a stream\n * ```typescript\n * const { first, last, count } = await app.query(\n * { stream: \"counter-1\" },\n * (event) => console.log(event.name, event.data)\n * );\n * console.log(`Found ${count} events from ${first?.id} to ${last?.id}`);\n * ```\n *\n * @example Query specific event types\n * ```typescript\n * const { count } = await app.query(\n * { name: \"UserCreated\", limit: 100 },\n * (event) => {\n * console.log(\"User created:\", event.data.email);\n * }\n * );\n * ```\n *\n * @example Query events in time range\n * ```typescript\n * const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);\n * const { count } = await app.query({\n * created_after: yesterday,\n * stream: \"user-123\"\n * });\n * console.log(`User had ${count} events in last 24 hours`);\n * ```\n *\n * @see {@link query_array} for loading events into memory\n */\n async query(\n query: Query,\n callback?: (event: Committed<TEvents, keyof TEvents>) => void\n ): Promise<{\n first?: Committed<TEvents, keyof TEvents>;\n last?: Committed<TEvents, keyof TEvents>;\n count: number;\n }> {\n return this._scoped(async () => {\n let first: Committed<TEvents, keyof TEvents> | undefined;\n let last: Committed<TEvents, keyof TEvents> | undefined;\n const count = await store().query<TEvents>((e) => {\n const gated = this.registry.query_gate(e.name as string)(e);\n if (!first) first = gated;\n last = gated;\n callback?.(gated);\n }, query);\n return { first, last, count };\n });\n }\n\n /**\n * Queries the event store and returns all matching events in memory.\n *\n * **Use with caution** - this loads all results into memory. For large result sets,\n * use {@link query} with a callback instead to process events incrementally.\n *\n * @param query - The query filter (same as {@link query})\n * @returns Array of all matching events\n *\n * @example Load all events for a stream\n * ```typescript\n * const events = await app.query_array({ stream: \"counter-1\" });\n * console.log(`Loaded ${events.length} events`);\n * events.forEach(event => console.log(event.name, event.data));\n * ```\n *\n * @example Get recent events\n * ```typescript\n * const recent = await app.query_array({\n * stream: \"user-123\",\n * limit: 10\n * });\n * ```\n *\n * @see {@link query} for large result sets\n */\n async query_array(\n query: Query\n ): Promise<Committed<TEvents, keyof TEvents>[]> {\n return this._scoped(async () => {\n const events: Committed<TEvents, keyof TEvents>[] = [];\n await store().query<TEvents>(\n (e) => events.push(this.registry.query_gate(e.name as string)(e)),\n query\n );\n return events;\n });\n }\n\n /**\n * Wipe the sensitive-data payload for every event on the stream — see\n * {@link IAct.forget}. Application-level half of #566.\n *\n * Throws on adapters without `Store.forget_pii`, invalidates the cache\n * entry for the stream, emits the `forgotten` lifecycle event with the\n * row count. Idempotent: a second call returns `{eventCount: 0}` and\n * does NOT re-emit.\n *\n * @param stream - Target stream.\n * @returns `{eventCount}` — number of events whose PII column was wiped.\n */\n async forget(stream: string): Promise<{ eventCount: number }> {\n return this._scoped(async () => {\n const s = store();\n if (!s.forget_pii) {\n throw new Error(\n `Store does not implement forget_pii — adapter cannot comply with sensitive-data erasure. ` +\n `Use an adapter that declares pii_isolation: true (e.g. @rotorsoft/act on the in-memory store).`\n );\n }\n const eventCount = await s.forget_pii(stream);\n await cache().invalidate(stream);\n if (eventCount > 0) {\n this.emit(\"forgotten\", { stream, at: new Date(), eventCount });\n }\n return { eventCount };\n });\n }\n\n /**\n * Processes pending reactions by draining uncommitted events from the event store.\n *\n * Runs a single drain cycle:\n * 1. Polls the store for streams with uncommitted events\n * 2. Leases streams to prevent concurrent processing\n * 3. Fetches events for each leased stream\n * 4. Executes matching reaction handlers\n * 5. Acknowledges successful reactions or blocks failing ones\n *\n * Drain uses a dual-frontier strategy to balance processing of new streams (lagging)\n * vs active streams (leading). The ratio adapts based on event pressure.\n *\n * Call `correlate()` before `drain()` to discover target streams. For a higher-level\n * API that handles debouncing, correlation, and signaling automatically, use {@link settle}.\n *\n * @param options - Drain configuration — see {@link DrainOptions} for fields\n * (`streamLimit`, `eventLimit`, `leaseMillis`).\n * @returns Drain statistics with fetched, leased, acked, and blocked counts\n *\n * @example In tests and scripts\n * ```typescript\n * await app.do(\"createUser\", target, payload);\n * await app.correlate();\n * await app.drain();\n * ```\n *\n * @example In production, prefer settle()\n * ```typescript\n * await app.do(\"CreateItem\", target, input);\n * app.settle(); // debounced correlate→drain, emits \"settled\"\n * ```\n *\n * @see {@link settle} for debounced correlate→drain with lifecycle events\n * @see {@link correlate} for dynamic stream discovery\n * @see {@link start_correlations} for automatic correlation\n */\n async drain(options: DrainOptions = {}): Promise<Drain<TEvents>> {\n // Validate the runtime knobs before anything runs (a bad leaseMillis /\n // streamLimit / eventLimit throws ZodError here, not on the first cycle).\n resolveDrainConfig(options);\n // #803: writer-only instances skip the local reaction pipeline.\n // Return an empty Drain result so call sites that aggregate (e.g.,\n // `settle` listeners) keep working without special-casing.\n if (!this._drain)\n return { fetched: [], leased: [], acked: [], blocked: [] };\n return this._scoped(() => this._drain_all(options));\n }\n\n /** Arm every active lane controller (ACT-1103). */\n private _arm_all(): void {\n for (const c of this._drain_controllers.values()) c.arm();\n }\n\n /**\n * Arm only the lane controllers whose reactions match the supplied\n * event names (ACT-1103 selective arming). Events with any dynamic\n * resolver fall back to `_arm_all()` via the `\"all\"` sentinel — the\n * resolver's lane isn't known until correlate runs the function.\n * Events with no reactions are skipped; `_event_to_lanes` doesn't\n * carry them. Returns true when any controller was armed (used by\n * the notify handler to decide whether to schedule a settle).\n */\n private _arm_for_event_names(names: Iterable<string>): boolean {\n const to_arm = new Set<string>();\n for (const name of names) {\n const set = this._event_to_lanes.get(name);\n if (set === undefined) continue;\n if (set === ALL_LANES) {\n this._arm_all();\n return true;\n }\n for (const lane of set) to_arm.add(lane);\n }\n if (to_arm.size === 0) return false;\n for (const lane of to_arm) this._drain_controllers.get(lane)?.arm();\n return true;\n }\n\n /** Drain every active lane controller in parallel and aggregate.\n *\n * Parallel — not sequential — so a slow lane's in-flight handler does\n * not block a fast lane's claim/dispatch/ack cycle. Each controller's\n * `claim()` is independent (filtered by lane); the store's\n * `SKIP LOCKED` keeps cross-controller races safe. Lifecycle events\n * (`acked`, `blocked`) may interleave by lane — listeners filter via\n * `lease.lane`. */\n private async _drain_all(options: DrainOptions): Promise<Drain<TEvents>> {\n const results = await Promise.all(\n [...this._drain_controllers.values()].map((c) => c.drain(options))\n );\n const fetched: Drain<TEvents>[\"fetched\"] = [];\n const leased: Lease[] = [];\n const acked: Lease[] = [];\n const blocked: BlockedLease[] = [];\n for (const r of results) {\n fetched.push(...r.fetched);\n leased.push(...r.leased);\n acked.push(...r.acked);\n blocked.push(...r.blocked);\n }\n return { fetched, leased, acked, blocked };\n }\n\n /**\n * Discovers and registers new streams dynamically based on reaction resolvers.\n *\n * Correlation enables \"dynamic reactions\" where target streams are determined at runtime\n * based on event content. For example, you might create a stats stream for each user\n * when they perform certain actions.\n *\n * This method scans events matching the query and identifies new target streams based\n * on reaction resolvers. It then registers these streams so they'll be picked up by\n * the next drain cycle.\n *\n * @param query - Query filter to scan for new correlations\n * @param query - Scan filter — see {@link Query} for fields (typically\n * `{ after: <event-id>, limit: <count> }`)\n * @returns Object with newly leased streams and last scanned event ID\n *\n * @example Manual correlation\n * ```typescript\n * // Scan for new streams\n * const { leased, last_id } = await app.correlate({ after: 0, limit: 100 });\n * console.log(`Found ${leased.length} new streams`);\n *\n * // Save last_id for next scan\n * await saveCheckpoint(last_id);\n * ```\n *\n * @example Dynamic stream creation\n * ```typescript\n * const app = act()\n * .withState(User)\n * .withState(UserStats)\n * .on(\"UserLoggedIn\")\n * .do(async (event) => [\"incrementLoginCount\", {}])\n * .to((event) => ({\n * target: `stats-${event.stream}` // Dynamic target per user\n * }))\n * .build();\n *\n * // Discover stats streams as users log in\n * await app.correlate();\n * ```\n *\n * @see {@link start_correlations} for automatic periodic correlation\n * @see {@link stop_correlations} to stop automatic correlation\n */\n async correlate(\n query: Query = { after: -1, limit: 10 }\n ): Promise<{ subscribed: number; last_id: number }> {\n // Writer-only instances skip dynamic stream discovery. The\n // {subscribed, last_id} pair returns the no-op result; the\n // checkpoint stays where it was.\n if (!this._drain) return { subscribed: 0, last_id: -1 };\n return this._scoped(async () => {\n const result = await this._correlate.correlate(query);\n // Newly-subscribed streams must arm their lane controllers, same\n // as reset/unblock: a lane worker's tick can disarm on an empty\n // claim in the window before the subscription lands, and nothing\n // re-arms until an unrelated commit — starving the fresh stream\n // on an otherwise idle system.\n if (result.subscribed > 0 && this._reactive_events.size > 0)\n this._arm_all();\n return result;\n });\n }\n\n /**\n * Starts automatic periodic correlation worker for discovering new streams.\n *\n * The correlation worker runs in the background, scanning for new events and identifying\n * new target streams based on reaction resolvers. It maintains a sliding window that\n * advances with each scan, ensuring all events are eventually correlated.\n *\n * This is useful for dynamic stream creation patterns where you don't know all streams\n * upfront - they're discovered as events arrive.\n *\n * **Note:** Only one correlation worker can run at a time per Act instance.\n *\n * @param query - Query filter for correlation scans — see {@link Query}\n * (typically `{ after: -1, limit: 100 }`)\n * @param frequency - Correlation frequency in milliseconds (default: 10000)\n * @param callback - Optional callback invoked with newly discovered streams\n * @returns `true` if worker started, `false` if already running\n *\n * @example Start automatic correlation\n * ```typescript\n * // Start correlation worker scanning every 5 seconds\n * app.start_correlations(\n * { after: 0, limit: 100 },\n * 5000,\n * (leased) => {\n * console.log(`Discovered ${leased.length} new streams`);\n * }\n * );\n *\n * // Later, stop it\n * app.stop_correlations();\n * ```\n *\n * @example With checkpoint persistence\n * ```typescript\n * // Load last checkpoint\n * const lastId = await loadCheckpoint();\n *\n * app.start_correlations(\n * { after: lastId, limit: 100 },\n * 10000,\n * async (leased) => {\n * // Save checkpoint for next restart\n * if (leased.length) {\n * const maxId = Math.max(...leased.map(l => l.at));\n * await saveCheckpoint(maxId);\n * }\n * }\n * );\n * ```\n *\n * @see {@link correlate} for manual one-time correlation\n * @see {@link stop_correlations} to stop the worker\n */\n start_correlations(\n query: Query = {},\n frequency = 10_000,\n callback?: (subscribed: number) => void\n ): boolean {\n const started = this._correlate.start_polling(query, frequency, callback);\n return started;\n }\n\n /**\n * Stops the automatic correlation worker.\n *\n * Call this to stop the background correlation worker started by {@link start_correlations}.\n * This is automatically called when the Act instance is disposed.\n *\n * @example\n * ```typescript\n * // Start correlation\n * app.start_correlations();\n *\n * // Later, stop it\n * app.stop_correlations();\n * ```\n *\n * @see {@link start_correlations}\n */\n stop_correlations() {\n this._correlate.stop_polling();\n }\n\n /**\n * Cancels any pending or active settle cycle.\n *\n * @see {@link settle}\n */\n stop_settling() {\n this._settle.stop();\n }\n\n /**\n * Reset reaction stream watermarks and request a drain on the next\n * `drain()` / `settle()` cycle.\n *\n * Use this to replay events through projections (or other reaction targets)\n * after changing handler logic. Equivalent to calling `store().reset(streams)`\n * directly, but also raises the orchestrator's internal \"needs drain\" flag —\n * `store().reset(...)` alone leaves the flag untouched, so a settled app\n * would short-circuit and skip the replay.\n *\n * Pair with `app.settle()` (or a single `app.drain()` for small streams).\n * `settle()` loops correlate→drain until no progress is made, so one call\n * fully catches up paginated streams without forcing callers to roll\n * their own loop.\n *\n * @param input - Reaction target streams (e.g., projection names) to reset, or a {@link StreamFilter} for bulk operations\n * @returns Count of streams that were actually reset\n *\n * @example Rebuild a projection (production)\n * ```typescript\n * await app.reset([\"my-projection\"]);\n * app.settle({ eventLimit: 1000 }); // emits \"settled\" when fully replayed\n * ```\n *\n * @example Rebuild a projection (tests / scripts)\n * ```typescript\n * await app.reset([\"my-projection\"]);\n * await app.drain({ eventLimit: 1000 }); // small streams: one pass is enough\n * ```\n *\n * @see {@link Store.reset} for the underlying store primitive\n * @see {@link settle} for the debounced full-catch-up loop\n */\n async reset(input: string[] | StreamFilter): Promise<number> {\n return this._scoped(async () => {\n const count = await store().reset(input);\n if (count > 0 && this._reactive_events.size > 0) this._arm_all();\n return count;\n });\n }\n\n /**\n * Clear the blocked flag on streams without replaying their history.\n *\n * Use this to recover from a poison message after fixing the\n * underlying issue — the stream resumes from the next event after the\n * last successful ack, not from the beginning. Compare with\n * {@link reset}, which rebuilds from event 0 (suitable for projection\n * rebuilds, wrong for \"I fixed the bug, please retry\").\n *\n * Wraps `store().unblock(streams)` and raises the orchestrator's\n * internal \"needs drain\" flag so a settled app picks up the now-free\n * streams on the next cycle. Equivalent to calling `store().unblock(...)`\n * directly, but `store().unblock(...)` alone leaves the flag\n * untouched.\n *\n * @param input - Stream names to unblock, or a {@link StreamFilter} for bulk recovery\n * @returns Count of streams that were actually flipped (were blocked)\n *\n * @example Recover from a 4xx webhook after fixing the bug\n * ```typescript\n * await app.unblock([\"webhooks-out-customer-42\"]);\n * // The stream resumes from the next event, not from zero.\n * ```\n *\n * @see {@link Store.unblock} for the underlying store primitive\n * @see {@link reset} for the rebuild-from-zero alternative\n */\n async unblock(input: string[] | StreamFilter): Promise<number> {\n return this._scoped(async () => {\n const count = await store().unblock(input);\n if (count > 0 && this._reactive_events.size > 0) this._arm_all();\n return count;\n });\n }\n\n /**\n * Atomically wipe the store and rebuild it from an async stream of\n * committed events. The framework owns iteration, validation,\n * `drop_snapshots` filtering, `on_progress`, and the per-call\n * `old → new` causation remap; the adapter's {@link Store.restore}\n * driver supplies the transaction lifecycle and per-event insert.\n *\n * Throws if the adapter has no restore capability. Throws on the\n * first invalid event (negative version, malformed `created`) with\n * the running index in the message; atomic transaction rollback in\n * the adapter means a failing restore leaves the store byte-for-byte\n * unchanged.\n *\n * @param source - Async stream of events in target order. Streamed\n * rather than buffered so multi-million-event backups don't OOM.\n * Each event's original `id` is used as a causation lookup key but\n * never written through — adapters renumber densely.\n * @param opts - {@link ScanOptions}. `drop_snapshots` skips\n * `__snapshot__` events (counted in the result); `on_progress`\n * fires once per event.\n * @returns {@link ScanResult} with `kept`, `duration_ms`, and\n * `dropped` per-category counters.\n *\n * @example Round-trip a CSV backup\n * ```typescript\n * async function* parseCsv(blob: string) {\n * for (const line of blob.split(\"\\n\").slice(1)) {\n * const [id, name, data, stream, version, created, meta] = parse(line);\n * yield {\n * id: +id, name, data: JSON.parse(data), stream,\n * version: +version, created: new Date(created),\n * meta: JSON.parse(meta),\n * };\n * }\n * }\n * const result = await app.restore(parseCsv(csvBlob), {});\n * console.log(`Restored ${result.kept} events in ${result.duration_ms}ms`);\n * await cache().clear(); // operator's responsibility\n * ```\n *\n * @see {@link Store.restore} for the underlying driver-pattern primitive.\n */\n async restore(\n source: EventSource,\n opts: ScanOptions = {},\n sink?: EventSink\n ): Promise<ScanResult> {\n return this._scoped(async () => {\n const started = Date.now();\n // Dry-run: walk the source via scan without touching any sink\n // — same scan loop, no callback, no transaction, no capability\n // check. Returns the counts a destructive restore would land.\n if (opts.dry_run) {\n const partial = await scan(source, opts);\n return { ...partial, duration_ms: Date.now() - started };\n }\n // Default sink is the singleton store. Explicit `sink` lets\n // callers route to a different EventSink (another adapter, a\n // CsvFile, etc.) without binding the singleton.\n const target: EventSink =\n sink ??\n (() => {\n const s = store();\n if (!s.restore) throw new Error(\"adapter has no restore capability\");\n return s as EventSink;\n })();\n let kept = 0;\n let migrated = 0;\n let dropped = { closed_streams: 0, snapshots: 0 };\n await target.restore(async (callback) => {\n const partial = await scan(source, opts, callback);\n kept = partial.kept;\n migrated = partial.migrated;\n dropped = partial.dropped;\n });\n return { kept, migrated, dropped, duration_ms: Date.now() - started };\n });\n }\n\n /**\n * Return every currently-blocked stream position. Convenience wrapper\n * around `store().query_streams(cb, { blocked: true })` for the common\n * \"show me what's broken\" operational query.\n *\n * Results are ordered by stream name, paginated by `limit` (default\n * 100). Pass `after` to fetch the next page (keyset cursor on the\n * stream name). For richer queries — including blocked + source\n * filters, or full unblocked introspection — drop to\n * `store().query_streams(...)` directly.\n *\n * @returns Array of {@link StreamPosition} for currently-blocked streams.\n *\n * @example Discover and recover\n * ```typescript\n * const blocked = await app.blocked_streams();\n * console.table(blocked.map(({ stream, retry, error }) => ({ stream, retry, error })));\n *\n * // Operator investigates, then bulk-unblocks the family:\n * await app.unblock({ stream: \"^webhooks-out-\" });\n * ```\n */\n async blocked_streams(options?: {\n after?: string;\n limit?: number;\n }): Promise<StreamPosition[]> {\n return this._scoped(async () => {\n const positions: StreamPosition[] = [];\n await store().query_streams(\n (p) => {\n positions.push(p);\n },\n { blocked: true, after: options?.after, limit: options?.limit }\n );\n return positions;\n });\n }\n\n /**\n * Operator-driven store audit (#723).\n *\n * Walks the connected store and yields per-category findings —\n * each tagged with the remediation it suggests. Same operator-\n * driven category as `app.close()` / `app.reset()` /\n * `app.unblock()` / `app.blocked_streams()`: never auto-invoked by\n * the framework; the operator decides when to run it (CI gate,\n * scheduled job, ad-hoc forensics) and what to do with the\n * findings.\n *\n * Categories are independent — pass a subset to scope the work,\n * or omit to run everything:\n *\n * ```typescript\n * // Targeted: schema drift + deprecated-event load only\n * for await (const f of app.audit([\"schema\", \"deprecated-load\"], {\n * query: { created_after: lastScan },\n * thresholds: { deprecatedLoadShareMin: 0.10 },\n * })) {\n * await escalate(f);\n * }\n *\n * // Full audit, default thresholds\n * for await (const f of app.audit()) console.log(f);\n * ```\n *\n * Returns an `AsyncIterable` so callers can `break` early — the\n * underlying store paginations respect the iterator protocol and\n * stop cleanly. Each finding is emitted independently, so\n * pipelining into Slack / persistence / further analysis works\n * without buffering the full report in memory.\n *\n * Findings shape — see {@link AuditFinding}. The discriminated\n * union carries enough context for the operator to act on each\n * finding directly: stream id, event id, recommendation hints.\n *\n * @param categories - Subset of categories to run (default: all).\n * @param options - Query window + per-category thresholds.\n * @returns Async iterable of {@link AuditFinding}.\n */\n async *audit(\n categories?: AuditCategory[],\n options?: AuditOptions\n ): AsyncIterable<AuditFinding> {\n // Drive the audit generator one step at a time INSIDE `_scoped`, so the\n // `store()` calls in its body resolve the scoped bag during lazy\n // iteration. A plain `return audit(...)` would run the generator body in\n // the consumer's `for await` frame, outside any scope — resolving the\n // singleton store and auditing the wrong tenant (#1317). For a\n // non-scoped Act `_scoped(fn)` is just `fn()`, so this is a no-op.\n const it = audit(this._audit_deps, categories, options)[\n Symbol.asyncIterator\n ]();\n while (true) {\n const { value, done } = await this._scoped(() => it.next());\n if (done) break;\n yield value;\n }\n }\n\n /**\n * Bulk-update scheduling priority for streams matching `filter`.\n *\n * Operator-grade override of the `claim()` lagging-frontier\n * ordering (ACT-102). Useful when a long-running replay needs to\n * jump ahead of other lagging streams, or when a no-longer-urgent\n * job should yield slots back to the rest. Build-time priorities\n * (set via the resolver's `priority` field) are subject to a\n * `max()` invariant across reactions; this API ignores that and\n * sets the priority outright on every matching row.\n *\n * Filter shape mirrors {@link query} / {@link Store.query_streams}:\n * `stream` / `source` are regex by default, exact with the\n * `*_exact` flags; `blocked` restricts to blocked or unblocked\n * rows. **An empty filter (`{}`) updates every registered stream.**\n *\n * @param filter - Selection criteria (regex by default).\n * @param priority - New priority value. Set as-is — no clamp.\n * @returns Count of streams whose priority changed.\n *\n * @example Boost a specific projection mid-replay\n * ```typescript\n * await app.prioritize({ stream: \"^proj-orders$\", stream_exact: false }, 10);\n * ```\n *\n * @example Drop all audit projections to background\n * ```typescript\n * await app.prioritize({ source: \"^audit-\" }, -5);\n * ```\n *\n * @example Reset everyone to default\n * ```typescript\n * await app.prioritize({}, 0);\n * ```\n *\n * @see {@link Store.prioritize} for the underlying primitive\n * @see {@link claim} for how priority biases scheduling\n */\n async prioritize(filter: StreamFilter, priority: number): Promise<number> {\n return this._scoped(() => store().prioritize(filter, priority));\n }\n\n /**\n * Close the books — guard, archive, truncate, and optionally restart streams.\n *\n * Safely removes historical events from the operational store:\n *\n * 1. **Correlate** — discover pending reaction targets\n * 2. **Safety check** — skip streams with pending reactions (skipped when no reactive events)\n * 3. **Guard** — commit `__tombstone__` with `expectedVersion` to block concurrent writes\n * 4. **Load state** — for streams in `snapshots`, load final state while guarded (no races)\n * 5. **Archive** — user callback per stream (abort-all on failure, streams are guarded)\n * 6. **Truncate + seed** — atomic: delete all events, insert `__snapshot__` or `__tombstone__`\n * 7. **Cache** — invalidate (tombstoned) or warm (restarted)\n * 8. **Emit \"closed\"** — lifecycle event with results\n *\n * Targets carrying `before` take the **windowed** branch instead —\n * close the books on a rolling window: probe the min consumer\n * watermark (so the boundary never rises past a lagging reaction),\n * run the archive callback against the cutoff, then prune the prefix\n * below the closest safe `__snapshot__`. No tombstone guard (the\n * pre-cutoff prefix is immutable), no seed, cache untouched — the\n * stream stays live and keeps accepting actions. Requires the state\n * to snapshot via `.snap(...)`; no qualifying snapshot ⇒ the stream\n * lands in `skipped` (retry after the next snapshot). Windowed\n * entries in the result echo `before` and carry the surviving\n * boundary snapshot as `committed`.\n *\n * @param targets - Per-stream close options (stream, restart?, archive?, before?)\n * @returns `{ truncated: TruncateResult, skipped: string[] }`\n *\n * @example Archive and close\n * ```typescript\n * await app.close([\n * { stream: \"order-123\", archive: async () => { await archiveToS3(\"order-123\"); } },\n * { stream: \"order-456\" },\n * ]);\n * ```\n *\n * @example Close with restart (state loaded automatically after guard)\n * ```typescript\n * await app.close([\n * { stream: \"counter-1\", restart: true },\n * { stream: \"counter-2\" }, // tombstoned\n * ]);\n * ```\n *\n * @example Windowed close — keep the last 180 days of real events\n * ```typescript\n * const cutoff = new Date();\n * cutoff.setDate(cutoff.getDate() - 180);\n * await app.close([\n * {\n * stream: \"ledger-acme\",\n * before: cutoff,\n * archive: async () => { await archiveToS3(\"ledger-acme\", cutoff); },\n * },\n * ]);\n * ```\n */\n /**\n * After a close, forget any target whose subscription row the truncate\n * removed, so a later correlate can re-subscribe it (#1398). Restart\n * targets keep their row, so only fully-retired streams are forgotten.\n */\n private _forget_closed_subscriptions(result: CloseResult): void {\n const retired = [...result.truncated.entries()]\n .filter(([, r]) => r.committed.name === TOMBSTONE_EVENT)\n .map(([stream]) => stream);\n if (retired.length) this._correlate.forget_subscribed(retired);\n }\n\n async close(targets: CloseTarget[]): Promise<CloseResult> {\n if (!targets.length) return { truncated: new Map(), skipped: [] };\n\n return this._scoped(async () => {\n // Correlate first so dynamic reaction targets are discovered before\n // the safety check examines subscription positions.\n await this.correlate({ limit: 1000 });\n\n // Synthesize an actor for the close transaction so user-supplied\n // correlators can still tag tenant context / trace ids.\n const close_actor = { id: \"$close\", name: \"close\" };\n const result = await run_close_cycle(targets, {\n reactive_events_size: this._reactive_events.size,\n event_to_state: this._event_to_state,\n load: this._es.load,\n tombstone: this._es.tombstone,\n logger: this._logger,\n correlation: close_correlation(this._correlator, close_actor),\n with_stream_lock: (stream, work) => this._with_close_lock(stream, work),\n });\n\n this._forget_closed_subscriptions(result);\n this.emit(\"closed\", result);\n return result;\n });\n }\n\n /**\n * Debounced, non-blocking correlate→drain cycle.\n *\n * Call this after `app.do()` (or `app.reset()`) to schedule a background\n * drain. Multiple rapid calls within the debounce window are coalesced\n * into a single cycle. Runs correlate→drain in a loop until a pass makes\n * no progress — no new subscriptions, no acks, no blocks — then emits\n * the `\"settled\"` lifecycle event. This means a single `settle()` call\n * fully catches up paginated streams (e.g. after `reset()` on a long\n * projection) without forcing callers to loop.\n *\n * @param options - Settle configuration — see {@link SettleOptions} for fields:\n * `debounceMs` (default 10), `correlate` (default `{ after: -1, limit: 100 }`),\n * `maxPasses` (default `Infinity` — kill-switch for runaway loops),\n * `streamLimit` (default 10), `eventLimit` (default 10),\n * `leaseMillis` (default 10000).\n *\n * @example API mutations\n * ```typescript\n * await app.do(\"CreateItem\", target, input);\n * app.settle(); // non-blocking, returns immediately\n *\n * app.on(\"settled\", (drain) => {\n * // notify SSE clients, invalidate caches, etc.\n * });\n * ```\n *\n * @see {@link drain} for single synchronous drain cycles\n * @see {@link correlate} for manual correlation\n */\n settle(options: SettleOptions = {}): void {\n // Validate the runtime knobs before anything runs (a bad debounceMs /\n // leaseMillis / maxPasses throws ZodError here, not on the first pass).\n resolveSettleConfig(options);\n // #803: writer-only instances skip settle entirely. The bootstrap\n // pattern `app.on(\"committed\", () => app.settle())` keeps working —\n // it just runs zero work on writers.\n if (!this._drain) return;\n this._settle.schedule(options);\n }\n}\n","/**\n * @module event-versions\n * @category Internal\n *\n * Auto-deprecation of legacy event versions via the `_v<digits>` naming\n * convention (ACT-403).\n *\n * Act's schema-evolution pattern keeps the old and new event names alive\n * forever — the old name on the read path (reducers), the new on the write\n * path (emissions). This module reads the convention to identify legacy\n * versions automatically; the framework then enforces \"emit only the\n * current version\" at build time and warns at runtime for dynamic emits.\n *\n * Convention pin: only `_v<digits>` with digits ≥ 2 counts as a version\n * suffix. `Foo_v1` is just a literal event name (the base `Foo` is\n * implicitly v1). Pinning here keeps the contract surface small.\n *\n * @internal\n */\n\nconst VERSION_SUFFIX = /^(.+?)_v(\\d+)$/;\n\ntype Versioned = { version: number; name: string };\n\n/**\n * Splits an event name into (base, version). Names without a `_v<n≥2>`\n * suffix are returned as (name, 1) — the base is its own implicit v1.\n */\nfunction parse(name: string): { base: string; version: number } {\n const m = name.match(VERSION_SUFFIX);\n if (m) {\n const v = Number.parseInt(m[2], 10);\n if (v >= 2) return { base: m[1], version: v };\n }\n return { base: name, version: 1 };\n}\n\n/**\n * Returns the set of event names that are deprecated by virtue of having\n * a higher-numbered sibling in the registry. The highest version in each\n * group is the current version; every lower version is deprecated.\n *\n * Gaps are allowed: `{Foo, Foo_v3}` → `Foo` is deprecated, `Foo_v3` is\n * current. The framework picks the max regardless of contiguity.\n *\n * Single-version groups (no siblings) yield no deprecations.\n *\n * @internal\n */\nexport function deprecated_event_names(names: Iterable<string>): Set<string> {\n const groups = new Map<string, Versioned[]>();\n for (const name of names) {\n const { base, version } = parse(name);\n const list = groups.get(base);\n if (list) list.push({ version, name });\n else groups.set(base, [{ version, name }]);\n }\n const deprecated = new Set<string>();\n for (const list of groups.values()) {\n if (list.length < 2) continue;\n // Two names mapping to the same numeric version (e.g. a leading-zero\n // `Foo_v02` alongside `Foo_v2`) can't both be a distinct version — one\n // is a typo. Left unguarded, the sort below would flag whichever lands\n // second, so declaration order would decide which one is \"current\",\n // and the real current event could be marked deprecated (a static\n // `.emit(...)` on it would then throw at build). Reject the collision\n // with a clear, order-independent error instead.\n const by_version = new Map<number, string>();\n for (const { version, name } of list) {\n const clash = by_version.get(version);\n if (clash)\n throw new Error(\n `duplicate event version: ${clash} and ${name} both map to version ${version} — ` +\n \"leading zeros in a `_v<n>` suffix are not allowed; use a single canonical spelling\"\n );\n by_version.set(version, name);\n }\n list.sort((a, b) => b.version - a.version); // descending\n // index 0 is current; the rest are deprecated\n for (let i = 1; i < list.length; i++) deprecated.add(list[i].name);\n }\n return deprecated;\n}\n\n/**\n * Given a deprecated event name and the full set of event names in its\n * registry, returns the current (highest-version) sibling. Used to build\n * actionable error messages — \"use `Foo_v3` instead.\"\n *\n * Returns `undefined` if the event has no higher-versioned sibling (which\n * means the caller's classification is stale or wrong).\n *\n * @internal\n */\nexport function current_version_of(\n deprecated_name: string,\n all_names: Iterable<string>\n): string | undefined {\n const target = parse(deprecated_name);\n let highest: Versioned | undefined;\n for (const name of all_names) {\n const { base, version } = parse(name);\n if (base !== target.base) continue;\n if (!highest || version > highest.version) highest = { version, name };\n }\n return highest && highest.version > target.version ? highest.name : undefined;\n}\n","import type { QueryStreams, Store, StreamPosition } from \"../types/index.js\";\n\n/** Streams read per page when walking the whole table. */\nexport const DEFAULT_STREAM_PAGE = 500;\n\n/**\n * Walks EVERY stream matching `query`, paging with the keyset cursor.\n *\n * `Store.query_streams` defaults to `limit: 100`, so a caller that wants\n * the whole table must page — passing no query silently truncates at the\n * first page, which is a false all-clear for anything that reports on\n * what it found.\n *\n * The cursor is the last stream name the callback saw; results are\n * ordered by stream name, so a short page means the walk is done.\n *\n * @param store - Store to walk.\n * @param callback - Invoked once per matching position, in name order.\n * @param query - Optional filter. A caller-supplied `limit` sets the page\n * size (the walk still visits every match); `after` seeds the cursor.\n * @returns The total number of positions emitted.\n *\n * @internal\n */\nexport async function walk_streams(\n store: Store,\n callback: (position: StreamPosition) => void,\n query?: Omit<QueryStreams, \"after\" | \"limit\"> & {\n after?: string;\n limit?: number;\n }\n): Promise<number> {\n const page_size = query?.limit ?? DEFAULT_STREAM_PAGE;\n let after = query?.after;\n let total = 0;\n for (;;) {\n let last: string | undefined;\n const { count } = await store.query_streams(\n (position) => {\n last = position.stream;\n callback(position);\n },\n { ...query, after, limit: page_size }\n );\n total += count;\n if (count < page_size) return total;\n after = last;\n }\n}\n","/**\n * @module audit\n * @category Internal\n *\n * Operator-driven store audit (#723).\n *\n * Walks the connected store and yields per-category {@link AuditFinding}s.\n * Each category answers a different \"what should I do with this store?\"\n * question and pairs with a remediation:\n *\n * - `schema` → fix the data model (poison events, unknown names)\n * - `close-candidate` → `app.close([...])`\n * - `restart-candidate` → `app.close([{stream, restart:true}, …])`\n * - `deprecated-load` → `app.close([...])` on the heaviest carriers\n * - `reaction-health` → `app.unblock(...)` / `app.reset(...)`\n * - `snapshot-drift` → manual `load({snap:true})` or wait for policy\n * - `routing-health` → restart-with-new-config to re-lane\n * - `correlation-gaps` → fix upstream correlator misconfig\n * - `clock-anomalies` → infra remediation (clock skew)\n *\n * ## Single-scan multiplex (efficiency contract)\n *\n * Earlier draft had each category run its own `store.query(...)`,\n * which meant N requested categories → N table walks. Bad for large\n * stores. Refactored to a pass-based design: each category is a\n * factory that returns an {@link AuditPass} with optional per-row\n * callbacks (`on_event` / `on_stream` / `on_stat`) and a `finalize` hook\n * for any second-pass work. The dispatcher determines the UNION of\n * required data sources, runs each *once*, and broadcasts each row\n * to all interested passes. Worst case: three scans total (events,\n * streams, stats) regardless of how many categories the operator\n * requested. Most categories also share state — close-candidate and\n * restart-candidate both consume the same `on_stat` stream; schema,\n * correlation-gaps, and clock-anomalies all hang off the same\n * `on_event` broadcast.\n *\n * Categories that need follow-up work (snapshot-drift's per-stream\n * snapshot lookup, correlation-gaps' orphan-id check after collecting\n * ids) do that in their `finalize` hook with their own targeted store\n * calls — keeps the shared scan path minimal.\n *\n * Isolated from orchestration internals — `act.ts` builds the\n * {@link AuditDeps} bag at `.build()` time and hands it here via\n * a one-liner. The audit module never reaches into\n * `internal/{event-sourcing,drain-cycle,settle,close-cycle}.ts`; it\n * only reads through the deps interface and the public `Store`\n * surface. Same shape as `act-tck` within the workspace — a peer of\n * orchestration, not entangled with its private mechanics.\n *\n * @internal\n */\n\nimport { SNAP_EVENT } from \"../ports.js\";\nimport type {\n AuditCategory,\n AuditFinding,\n AuditOptions,\n Committed,\n Logger,\n Schemas,\n State,\n Store,\n StreamPosition,\n StreamStats,\n} from \"../types/index.js\";\nimport {\n current_version_of,\n deprecated_event_names,\n} from \"./event-versions.js\";\nimport { pii_fields } from \"./sensitive.js\";\nimport { walk_streams } from \"./walk-streams.js\";\n\n/**\n * Snapshot of orchestrator state the audit reads. Built once at\n * `app.build()`; the audit treats it as immutable for the duration\n * of a call. The orchestrator never passes its own private maps in\n * directly — this bag is the abstraction boundary so a future\n * orchestration refactor can't accidentally entangle with audit\n * logic.\n */\nexport type AuditDeps = {\n readonly store: () => Store;\n readonly logger: Logger;\n /** event-name → state that registers it (for schema validation). */\n readonly event_to_state: ReadonlyMap<string, State<any, any, any>>;\n /** state-name → state (for snapshot-supported check on restart-candidate). */\n readonly states: ReadonlyMap<string, State<any, any, any>>;\n /** Declared drain lanes (for routing-health unknown-lane). */\n readonly declared_lanes: ReadonlySet<string>;\n /**\n * Event names that the registry has at least one reaction for —\n * used by routing-health to detect \"registered but unrouted\"\n * events. Normalized down from the internal `event_to_lanes` map\n * (which carries lane-set details audit doesn't need).\n */\n readonly routed_events: ReadonlySet<string>;\n};\n\n/**\n * Defaults applied when the operator doesn't override via\n * {@link AuditOptions.thresholds}. Values land where most workloads\n * find them operationally useful — operators can tune per call.\n */\nconst DEFAULTS = {\n idle_days: 90,\n restart_min: 10_000,\n stuck_minutes: 30,\n deprecated_min: 0.1,\n drift_min: 500,\n near_block: 3,\n};\n\nconst ALL_CATEGORIES = [\n \"schema\",\n \"close-candidate\",\n \"restart-candidate\",\n \"deprecated-load\",\n \"reaction-health\",\n \"snapshot-drift\",\n \"routing-health\",\n \"correlation-gaps\",\n \"clock-anomalies\",\n] as const satisfies readonly AuditCategory[];\n\n/**\n * A single audit category, expressed as a stream-consumer:\n *\n * - `on_event` / `on_stream` / `on_stat` are called by the dispatcher\n * during the shared scans. Each is optional; the dispatcher uses\n * the presence/absence to decide which scans to run.\n * - `finalize` runs after all shared scans complete. Categories that\n * need targeted follow-up store calls (snapshot-drift fetches the\n * last `__snapshot__` per drifted stream; correlation-gaps cross-\n * checks causations against the collected id set) do that here.\n * - `drain` is called last and returns the accumulated findings.\n */\ntype AuditPass = {\n category: AuditCategory;\n on_event?: (e: Committed<Schemas, string>) => void;\n on_stream?: (p: StreamPosition) => void;\n on_stat?: (stream: string, s: StreamStats<Schemas>) => void;\n finalize?: (deps: AuditDeps) => Promise<void>;\n drain: () => AuditFinding[];\n};\n\ntype PassFactory = (deps: AuditDeps, options: AuditOptions) => AuditPass;\n\n/**\n * Top-level audit dispatcher. Single-scan multiplex: each requested\n * category contributes a `AuditPass`, the dispatcher determines the\n * union of required data sources (events / streams / stats), runs\n * each once, broadcasts rows, and yields per-category findings in\n * the order the categories were requested.\n *\n * Callers can `break` the iteration early — the underlying scan\n * loops have already completed by the time yield starts, so early\n * break only saves the iteration over already-collected findings.\n * (Per-row early termination during a scan isn't feasible without\n * coordination across passes; the audit is bounded by `options.query`\n * scoping rather than mid-scan cancellation.)\n */\nexport async function* audit(\n deps: AuditDeps,\n categories?: AuditCategory[],\n options: AuditOptions = {}\n): AsyncIterable<AuditFinding> {\n const requested = new Set<AuditCategory>(categories ?? [...ALL_CATEGORIES]);\n // Preserve a deterministic category order (matches ALL_CATEGORIES\n // declaration) so output ordering doesn't depend on the order\n // operators list categories in their call.\n const ordered_categories = ALL_CATEGORIES.filter((c) => requested.has(c));\n const passes: AuditPass[] = ordered_categories.map((c) =>\n PASS_FACTORIES[c](deps, options)\n );\n\n // Determine scan needs. `some(...)` short-circuits — three trivial\n // walks at worst.\n const need_stats = passes.some((p) => p.on_stat !== undefined);\n const need_streams = passes.some((p) => p.on_stream !== undefined);\n const need_events = passes.some((p) => p.on_event !== undefined);\n\n if (need_stats) {\n // Exclude `__snapshot__` so `head` and `count` are DOMAIN figures.\n // A snapshot is committed right after the domain event that triggered\n // it, so without this the head of any snapshotting stream is\n // `__snapshot__` — and every pass that gates on the head name\n // (`startsWith(\"__\")` → \"already closed\") silently skips the stream.\n // Same reasoning as `scan_stream_heads` in the close cycle.\n //\n // `__tombstone__` is deliberately NOT excluded: a tombstoned stream\n // really is closed, and the head-name gates are what recognize it.\n const stats = await deps\n .store()\n .query_stats<Schemas>(\n {},\n { count: true, names: true, exclude: [SNAP_EVENT] }\n );\n for (const [stream, s] of stats) {\n for (const p of passes) p.on_stat?.(stream, s);\n }\n }\n\n if (need_streams) {\n // Paged — `query_streams` defaults to 100, and an audit that inspects\n // only the first page reports a false all-clear for every stream that\n // sorts past it.\n await walk_streams(deps.store(), (pos) => {\n for (const p of passes) p.on_stream?.(pos);\n });\n }\n\n if (need_events) {\n await deps.store().query<Schemas>((event) => {\n for (const p of passes) p.on_event?.(event);\n }, options.query);\n }\n\n // Async post-processing (per-stream queries, second-pass orphan\n // detection). Serial to avoid pool contention; categories are\n // independent so order doesn't matter semantically.\n for (const p of passes) await p.finalize?.(deps);\n\n // Yield findings in requested-category order.\n for (const p of passes) {\n for (const f of p.drain()) yield f;\n }\n}\n\n// =================== Pass factories ===================\n//\n// Each category is implemented as a closure-bound `AuditPass`. The\n// factory captures `deps` + relevant options + a `findings` array;\n// the returned pass exposes the per-row hooks the dispatcher calls.\n//\n// All findings are accumulated in a per-pass `findings` buffer and\n// returned from `drain()`. No yield-during-scan — that would couple\n// the pass to async iteration semantics and prevent the shared-scan\n// multiplexing.\n\n/**\n * `schema` — every event in the audit window is parsed against the\n * Zod schema the registry currently declares for its name. Two\n * failure modes: `unknown_event_name` (event sits on disk, registry\n * has no entry) and `schema_validation_failed` (event matches a\n * known name but fails the current Zod schema).\n */\nconst make_schema_pass: PassFactory = (deps) => {\n const findings: AuditFinding[] = [];\n return {\n category: \"schema\",\n on_event(event) {\n const name = String(event.name);\n const state = deps.event_to_state.get(name);\n if (!state) {\n // Skip framework markers — they're not user-declared.\n if (name.startsWith(\"__\")) return;\n findings.push({\n category: \"schema\",\n stream: event.stream,\n event_id: event.id,\n name,\n reason: \"unknown_event_name\",\n });\n return;\n }\n const schema = state.events[name];\n // `sensitive()` keys are split out of `data` into the pii sidecar at\n // commit — their absence from `data` is correct, not corruption. The\n // pass reads raw stored rows, so parsing against the full schema\n // reported every healthy sensitive event as invalid, one finding per\n // event, burying the real ones (#1424). Omit those keys instead; the\n // rest of the payload is still validated.\n const sensitive = pii_fields(schema);\n let parse_schema = schema;\n if (sensitive.length > 0) {\n const omitter = (\n schema as unknown as {\n omit?: (mask: Record<string, true>) => typeof schema;\n }\n ).omit;\n if (typeof omitter !== \"function\") {\n // A non-object schema (e.g. a union) whose variants carry pii —\n // the split keys can't be masked off, so any parse here is a\n // guaranteed false positive. Skip rather than cry wolf.\n return;\n }\n parse_schema = omitter.call(\n schema,\n Object.fromEntries(sensitive.map((f) => [f, true as const]))\n );\n }\n const parsed = parse_schema.safeParse(event.data);\n if (!parsed.success) {\n findings.push({\n category: \"schema\",\n stream: event.stream,\n event_id: event.id,\n name,\n reason: \"schema_validation_failed\",\n zod_error: parsed.error,\n });\n }\n },\n drain: () => findings,\n };\n};\n\n/**\n * `deprecated-load` — workspace-wide event-name histogram classified\n * by the framework's `_v<digits>` rule. Built from the shared `on_stat`\n * stream — accumulates per-name + per-stream totals in memory, then\n * emits one finding per deprecated event above the threshold during\n * `drain`.\n */\n/**\n * Per-state deprecation classification — mirrors the builder/registry\n * (`registry.deprecated_events(state_name)`), which group `_v<n>` families\n * strictly within one state's own event set. Classifying over the global\n * event-name union instead would conflate same-stem events across\n * unrelated states (a false-positive migration finding) and even throw on\n * a cross-state leading-zero version collision the builder accepted (#1310).\n * Returns a map of deprecated event name → its current (highest) sibling.\n */\nconst classify_deprecated_by_state = (\n deps: AuditDeps\n): ReadonlyMap<string, string> => {\n const names_by_state = new Map<State<any, any, any>, Set<string>>();\n for (const [name, state] of deps.event_to_state) {\n let set = names_by_state.get(state);\n if (!set) {\n set = new Set();\n names_by_state.set(state, set);\n }\n set.add(name);\n }\n const deprecated_to_current = new Map<string, string>();\n for (const names of names_by_state.values()) {\n for (const name of deprecated_event_names(names)) {\n // `current_version_of` is guaranteed defined for a deprecated name\n // within its own state's family.\n deprecated_to_current.set(name, current_version_of(name, names)!);\n }\n }\n return deprecated_to_current;\n};\n\nconst make_deprecated_load_pass: PassFactory = (deps, options) => {\n const share_min =\n options.thresholds?.deprecated_min ?? DEFAULTS.deprecated_min;\n const totals = new Map<string, number>();\n const per_stream = new Map<string, Map<string, number>>();\n return {\n category: \"deprecated-load\",\n on_stat(stream, { names }) {\n // Contract: query_stats was called with `{names: true}`,\n // so adapter populates `names` with positive integer counts.\n // No runtime fallback needed.\n for (const [name, count] of Object.entries(names!)) {\n totals.set(name, (totals.get(name) ?? 0) + count!);\n let m = per_stream.get(name);\n if (!m) {\n m = new Map();\n per_stream.set(name, m);\n }\n m.set(stream, count!);\n }\n },\n drain() {\n const findings: AuditFinding[] = [];\n const grand = [...totals.values()].reduce((s, n) => s + n, 0);\n if (grand === 0) return findings;\n // Per-state deprecation classification (not on-disk-driven, and not\n // over the global event-name union — see #1310).\n const deprecated = classify_deprecated_by_state(deps);\n const sorted = [...deprecated.keys()]\n .map((name) => ({ name, count: totals.get(name) ?? 0 }))\n .sort((a, b) => b.count - a.count);\n for (const { name, count } of sorted) {\n if (count === 0) continue;\n if (count / grand < share_min) continue;\n // `classify_deprecated_by_state` maps every deprecated name to its\n // current (highest-version) sibling within the same state.\n const current_version = deprecated.get(name)!;\n // per_stream is populated in lockstep with totals — name is guaranteed present.\n const top_streams = [...per_stream.get(name)!.entries()]\n .map(([stream, c]) => ({ stream, count: c }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 10);\n findings.push({\n category: \"deprecated-load\",\n name,\n current_version,\n total: count,\n top_streams,\n });\n }\n return findings;\n },\n };\n};\n\n/**\n * `close-candidate` — flags streams ripe for `app.close(...)`. Two\n * flavours: `idle` (head older than `idle_days`) and `terminal` (head\n * event name in operator-supplied `terminal_events` list). Each\n * finding carries `restart_supported` (state has `.snap()`).\n */\nconst make_close_candidate_pass: PassFactory = (deps, options) => {\n const idle_days = options.thresholds?.idle_days ?? DEFAULTS.idle_days;\n const terminal_events = new Set(options.thresholds?.terminal_events ?? []);\n const idle_cutoff = Date.now() - idle_days * 24 * 60 * 60 * 1000;\n const findings: AuditFinding[] = [];\n return {\n category: \"close-candidate\",\n on_stat(stream, { head }) {\n const head_name = String(head.name);\n if (head_name.startsWith(\"__\")) return; // already-closed or mid-truncate\n // All in-tree adapters return `created` as Date; the Date\n // constructor passes Date instances through unchanged, so a\n // single call shape works regardless.\n const head_time = head.created.getTime();\n const is_idle = head_time < idle_cutoff;\n const is_terminal = terminal_events.has(head_name);\n if (!is_idle && !is_terminal) return;\n findings.push({\n category: \"close-candidate\",\n stream,\n last_event_at: head.created.toISOString(),\n reason: is_terminal ? \"terminal\" : \"idle\",\n idle_days: is_idle\n ? Math.floor((Date.now() - head_time) / (24 * 60 * 60 * 1000))\n : undefined,\n restart_supported: restart_is_supported(deps, head_name),\n });\n },\n drain: () => findings,\n };\n};\n\n/**\n * `restart-candidate` — streams above `event_count_for_restart` whose\n * state declares `.snap()`. Reads from the shared `on_stat` stream.\n */\nconst make_restart_candidate_pass: PassFactory = (deps, options) => {\n const threshold = options.thresholds?.restart_min ?? DEFAULTS.restart_min;\n // Resolved in finalize — the shared stat scan excludes `__snapshot__`\n // (so heads and counts are domain figures), which means the snapshot\n // tally isn't in `names`. Candidates are streams above `restart_min`,\n // so this is a handful of targeted counts, not a second table walk.\n const candidates: Array<{ stream: string; count: number }> = [];\n const findings: AuditFinding[] = [];\n return {\n category: \"restart-candidate\",\n on_stat(stream, { head, count }) {\n // `count` always populated — query_stats is called with the flag set.\n if (count! < threshold) return;\n const head_name = String(head.name);\n if (head_name.startsWith(\"__\")) return;\n if (!restart_is_supported(deps, head_name)) return;\n candidates.push({ stream, count: count! });\n },\n async finalize(deps) {\n for (const { stream, count } of candidates) {\n let snaps = 0;\n await deps.store().query(\n () => {\n snaps++;\n },\n {\n stream,\n stream_exact: true,\n names: [SNAP_EVENT],\n with_snaps: true,\n }\n );\n findings.push({\n category: \"restart-candidate\",\n stream,\n count,\n snaps,\n });\n }\n },\n drain: () => findings,\n };\n};\n\n/**\n * `reaction-health` — surfaces blocked / near-block / stuck-backoff\n * streams. Reads from the shared `on_stream` stream-positions\n * broadcast.\n */\nconst make_reaction_health_pass: PassFactory = (_deps, options) => {\n const near_block = options.thresholds?.near_block ?? DEFAULTS.near_block;\n const stuck_minutes =\n options.thresholds?.stuck_minutes ?? DEFAULTS.stuck_minutes;\n const stuck_cutoff = Date.now() - stuck_minutes * 60 * 1000;\n const findings: AuditFinding[] = [];\n return {\n category: \"reaction-health\",\n on_stream(p) {\n if (p.blocked) {\n findings.push({\n category: \"reaction-health\",\n stream: p.stream,\n status: \"blocked\",\n retry: p.retry,\n reason: p.error || \"blocked without recorded error\",\n });\n return;\n }\n if (p.retry >= near_block) {\n findings.push({\n category: \"reaction-health\",\n stream: p.stream,\n status: \"near-block\",\n retry: p.retry,\n reason: `retry ${p.retry} ≥ near-block threshold ${near_block}`,\n });\n return;\n }\n if (\n p.leased_by &&\n p.leased_until &&\n p.leased_until.getTime() < stuck_cutoff\n ) {\n const minutes = Math.floor(\n (Date.now() - p.leased_until.getTime()) / (60 * 1000)\n );\n findings.push({\n category: \"reaction-health\",\n stream: p.stream,\n status: \"stuck-backoff\",\n retry: p.retry,\n reason: `lease expired ${minutes}m ago without release`,\n });\n }\n },\n drain: () => findings,\n };\n};\n\n/**\n * `snapshot-drift` — buffers candidate streams from the shared\n * `on_stat` pass (skipping non-snap states + tombstoned heads), then\n * does targeted per-stream lookups in `finalize` to find the last\n * `__snapshot__` event id and count events past it.\n */\nconst make_snapshot_drift_pass: PassFactory = (deps, options) => {\n const drift_min = options.thresholds?.drift_min ?? DEFAULTS.drift_min;\n // Streams the workspace pass identifies as drift candidates —\n // resolved in finalize with per-stream queries.\n const candidates: Array<{\n stream: string;\n total: number;\n }> = [];\n const findings: AuditFinding[] = [];\n return {\n category: \"snapshot-drift\",\n on_stat(stream, { head, count }) {\n // restart_is_supported() already filters out framework markers\n // (__snapshot__, __tombstone__) — neither name appears in any\n // user state's events map, so the snap check rejects them.\n if (!restart_is_supported(deps, String(head.name))) return;\n if (count! < drift_min) return; // upper-bound short-circuit\n candidates.push({\n stream,\n total: count!,\n });\n },\n async finalize(deps) {\n for (const { stream, total } of candidates) {\n let events_since_snap = total;\n let snap_at: number | undefined;\n // The shared stat scan excludes `__snapshot__` so every other\n // pass sees domain heads, which means the snapshot count isn't\n // in `names` — resolve it from this targeted lookup instead. A\n // stream with no snapshot yields nothing here and keeps\n // `events_since_snap = total`, the same answer as before.\n const collected: Array<{ id: number }> = [];\n await deps.store().query(\n (e) => {\n collected.push({ id: e.id });\n },\n {\n stream,\n stream_exact: true,\n names: [\"__snapshot__\"],\n backward: true,\n limit: 1,\n with_snaps: true,\n }\n );\n if (collected.length > 0) {\n snap_at = collected[0]!.id;\n let after = 0;\n await deps.store().query(\n () => {\n after++;\n },\n { stream, stream_exact: true, after: snap_at }\n );\n events_since_snap = after;\n }\n if (events_since_snap < drift_min) continue;\n findings.push({\n category: \"snapshot-drift\",\n stream,\n events_since_snap,\n snap_at,\n });\n }\n },\n drain: () => findings,\n };\n};\n\n/**\n * `routing-health` — `unknown-lane` from the streams-table pass +\n * `unrouted` from the stats pass. Reads from BOTH shared streams.\n */\nconst make_routing_health_pass: PassFactory = (deps) => {\n const findings: AuditFinding[] = [];\n const seen_event_names = new Set<string>();\n return {\n category: \"routing-health\",\n on_stream(p) {\n if (!p.lane) return; // default lane — never an unknown-lane finding\n if (deps.declared_lanes.has(p.lane)) return;\n findings.push({\n category: \"routing-health\",\n stream: p.stream,\n reason: \"unknown-lane\",\n lane: p.lane,\n });\n },\n on_stat(_stream, { names }) {\n for (const name of Object.keys(names!)) {\n seen_event_names.add(name);\n }\n },\n finalize() {\n for (const name of seen_event_names) {\n if (name.startsWith(\"__\")) continue;\n if (deps.routed_events.has(name)) continue;\n findings.push({\n category: \"routing-health\",\n stream: \"*\",\n reason: \"unrouted\",\n });\n }\n return Promise.resolve();\n },\n drain: () => findings,\n };\n};\n\n/**\n * `correlation-gaps` — collects ids + parent_ids during the shared\n * event pass; flags orphans in `drain`. No second store walk — the\n * id-set + the (id, parent) buffer are both populated in one pass.\n */\nconst make_correlation_gaps_pass: PassFactory = () => {\n const seen_ids = new Set<number>();\n const checks: Array<{ stream: string; id: number; parent_id: number }> = [];\n return {\n category: \"correlation-gaps\",\n on_event(e) {\n seen_ids.add(e.id);\n const causation = (e.meta as Record<string, unknown> | undefined)\n ?.causation as { event?: { id?: number } } | undefined;\n const parent_id = causation?.event?.id;\n if (parent_id !== undefined) {\n checks.push({ stream: e.stream, id: e.id, parent_id });\n }\n },\n drain() {\n const findings: AuditFinding[] = [];\n for (const { stream, id, parent_id } of checks) {\n if (!seen_ids.has(parent_id)) {\n findings.push({\n category: \"correlation-gaps\",\n stream,\n event_id: id,\n reason: \"orphan-parent\",\n });\n }\n }\n return findings;\n },\n };\n};\n\n/**\n * `clock-anomalies` — flags future timestamps + per-stream out-of-\n * order `created`. Single pass, per-stream \"last seen\" state in a\n * Map. Cheap.\n */\nconst make_clock_anomalies_pass: PassFactory = () => {\n const findings: AuditFinding[] = [];\n const last_per_stream = new Map<string, number>();\n return {\n category: \"clock-anomalies\",\n on_event(e) {\n // `created` is a Date instance per the Store contract.\n const created = e.created.getTime();\n if (created > Date.now()) {\n findings.push({\n category: \"clock-anomalies\",\n stream: e.stream,\n event_id: e.id,\n reason: \"future-created\",\n });\n }\n const prev = last_per_stream.get(e.stream);\n if (prev !== undefined && created < prev) {\n findings.push({\n category: \"clock-anomalies\",\n stream: e.stream,\n event_id: e.id,\n reason: \"out-of-order\",\n });\n }\n last_per_stream.set(e.stream, created);\n },\n drain: () => findings,\n };\n};\n\n/** Does the stream's owning state declare a `.snap()` reducer? */\nfunction restart_is_supported(\n deps: AuditDeps,\n head_event_name: string\n): boolean {\n const state = deps.event_to_state.get(head_event_name);\n return state?.snap !== undefined;\n}\n\n/** Factory registry — pass-creation indexed by category name. */\nconst PASS_FACTORIES: Record<AuditCategory, PassFactory> = {\n schema: make_schema_pass,\n \"deprecated-load\": make_deprecated_load_pass,\n \"close-candidate\": make_close_candidate_pass,\n \"restart-candidate\": make_restart_candidate_pass,\n \"reaction-health\": make_reaction_health_pass,\n \"snapshot-drift\": make_snapshot_drift_pass,\n \"routing-health\": make_routing_health_pass,\n \"correlation-gaps\": make_correlation_gaps_pass,\n \"clock-anomalies\": make_clock_anomalies_pass,\n};\n","/**\n * @module autoclose-policy\n * @category Internal\n *\n * Declarative close-policy options consumed by `.autocloses({...})`\n * (#838 / epic #802). Three optional fields cover the three\n * operational pressure points every real close policy traces back to:\n *\n * - `after` — time / compliance (\"autocloses **after** N days\")\n * - `is` — domain lifecycle (\"autocloses ... **is** Resolved\")\n * - `reaches` — resource (\"autocloses ... **reaches** 10k events\")\n *\n * Top-level fields combine with **AND** semantics. This captures the\n * common cooldown-after-terminal pattern that runs through almost\n * every business app — *\"close 90 days after `Resolved`\"*, *\"close 14\n * days after `Delivered`\"*, *\"close 30 days after a GDPR deletion\n * request\"*. All conditions must hold for the cycle to truncate.\n *\n * A separate `or: {...}` block opens an alternative path: when\n * present, the policy fires if **either** the top-level AND group\n * matches **or** any field inside `or` matches. Use it for safety\n * nets — *\"close (Resolved AND aged 90 days) OR if event count\n * reaches 10k\"*. The two-axis split mirrors the two ways close\n * policies appear in practice: primary close logic (AND-shaped) and\n * defensive backstops (OR-shaped).\n *\n * The state builder's `.autocloses(...)` overload distinguishes\n * function (predicate) from object (policy) and routes the latter\n * through {@link compile_autoclose_policy}, which validates via\n * {@link AutoclosePolicySchema} and returns the compiled predicate.\n * Operators with custom needs (per-stream metadata, multi-branch\n * AND/OR like \"(`Resolved` + 90d) OR (`Cancelled` + 30d)\") keep the\n * function form; the declarative form covers the 90% case.\n *\n * Validation runs at the builder call (`act().build()` time), so\n * misconfiguration — empty bag, sub-1 `reaches`, sub-minute `after`,\n * empty `is`, empty `or`, nested `or` inside `or`, unknown keys —\n * throws at build, not on the first cycle tick.\n *\n * @internal\n */\n\nimport { z } from \"zod\";\nimport type { AutoclosePredicate, Schemas } from \"../types/action.js\";\n\n/**\n * One day in epoch milliseconds. The close surface is day-denominated\n * throughout — policies declare `{ days }`, the State carries\n * `autoclose_*_days`, and the reaction thinks in day offsets. This\n * constant (with {@link days_after} / {@link days_before_now}) is the\n * single place the closing process touches epoch arithmetic, because\n * `Date` itself has no other currency.\n */\nconst DAY_MS = 86_400_000;\n\n/**\n * Lower bound on a resolved `after` window: one minute, expressed in\n * days. Sub-minute cooldowns are almost always misconfiguration.\n * Rejecting at build keeps the failure mode noisy.\n */\nconst MIN_AFTER_DAYS = 1 / 1440;\n\n/**\n * Lower bound on a resolved `keep` window: one full day. The close\n * cycle is low-cadence, non-priority housekeeping — a rolling window\n * shorter than a day signals misconfiguration. Real retention\n * contracts (180 days, 7 years) are days and up.\n */\nconst MIN_KEEP_DAYS = 1;\n\n/** The `Date` that lies `days` after `date`. @internal */\nexport function days_after(date: Date, days: number): Date {\n return new Date(date.getTime() + days * DAY_MS);\n}\n\n/** The `Date` that lies `days` in the past. @internal */\nexport function days_before_now(days: number): Date {\n return new Date(Date.now() - days * DAY_MS);\n}\n\n/**\n * Day-denominated window shared by `after` (terminate cooldown) and\n * `keep` (rolling retention). Fractional days accepted; windows below\n * the field's floor reject at build.\n *\n * @internal\n */\nconst window_schema = (\n field: \"after\" | \"keep\",\n min_days: number,\n floor: string\n) =>\n z\n .object({\n days: z\n .number({ message: `autocloses: ${field}.days must be a number` })\n .positive(`autocloses: ${field}.days must be > 0`),\n })\n .refine((o) => o.days >= min_days, {\n message: `autocloses: ${field} resolves to < ${floor}, which is too short to be a meaningful retention window`,\n });\n\nconst AfterSchema = window_schema(\"after\", MIN_AFTER_DAYS, \"one minute\");\n\nconst KeepSchema = window_schema(\"keep\", MIN_KEEP_DAYS, \"one day\");\n\nconst IsSchema = z.union([\n z.string().min(1, \"autocloses: is must be a non-empty event name\"),\n z\n .array(\n z.string().min(1, \"autocloses: is entries must be non-empty event names\")\n )\n .min(1, \"autocloses: is must include at least one event name\")\n .readonly(),\n]);\n\nconst ReachesSchema = z\n .number({ message: \"autocloses: reaches must be a number\" })\n .int(\"autocloses: reaches must be an integer\")\n .min(1, \"autocloses: reaches must be >= 1\");\n\n/**\n * Schema for the `or: {...}` block — the OR-shaped alternative path.\n * Same field set as the top-level policy minus `or` itself (so nested\n * `or` inside `or` rejects via `.strict()` instead of recursing). At\n * least one field required; empty `{}` is a misconfiguration.\n *\n * @internal\n */\nconst OrBlockSchema = z\n .object({\n after: AfterSchema.optional(),\n is: IsSchema.optional(),\n reaches: ReachesSchema.optional(),\n })\n .strict()\n .refine(\n (o) =>\n o.after !== undefined || o.is !== undefined || o.reaches !== undefined,\n {\n message:\n \"autocloses: `or` block must include at least one of after / is / reaches\",\n }\n );\n\n/**\n * Zod schema for the declarative {@link AutoclosePolicy} bag.\n * Internal `const` per the config-validation-schema standard (CLAUDE.md\n * \"Config-validation schemas\") — the public surface is the inferred\n * {@link AutoclosePolicy} type and the `.autocloses({...})` overload,\n * never this schema. `.strict()` rejects unknown keys so typos surface\n * at build instead of being silently ignored.\n *\n * @internal\n */\nconst AutoclosePolicySchema = z\n .object({\n after: AfterSchema.optional(),\n is: IsSchema.optional(),\n reaches: ReachesSchema.optional(),\n or: OrBlockSchema.optional(),\n keep: KeepSchema.optional(),\n })\n .strict()\n .refine(\n (o) =>\n o.after !== undefined ||\n o.is !== undefined ||\n o.reaches !== undefined ||\n o.or !== undefined ||\n o.keep !== undefined,\n {\n message:\n \"autocloses: at least one of after / is / reaches / or / keep must be specified — empty `{}` is a misconfiguration\",\n }\n );\n\n/**\n * Declarative close-policy options consumed by `.autocloses({...})`.\n * Top-level fields are AND-combined; the optional `or` block opens an\n * alternative OR-path. Omitted fields contribute nothing — they do\n * not mean \"match everything.\"\n *\n * @property after - Close when `head.created` is at least the resolved\n * window in the past. Days are the close surface's only unit;\n * fractional `days` cover sub-day cooldowns (`{ days: 1/24 }` is one\n * hour) without introducing another denomination.\n * @property is - Close when `head.name` matches. String for the\n * single-terminal-event case (the most common); `readonly string[]`\n * for multi-terminal states (`Order: Shipped | Delivered |\n * Cancelled`).\n * @property reaches - Close when the stream's event count is `>= N`\n * (inclusive — fires the moment the threshold is reached).\n * @property or - Alternative OR-path. When present, the policy fires\n * if EITHER the top-level AND group matches OR any field inside\n * `or` matches. Used for safety-net backstops layered onto a\n * primary cooldown policy (e.g. *\"(Resolved AND 90 days) OR reaches\n * 10k\"*). Nested `or` inside `or` rejects at build time.\n * @property keep - Rolling-window retention (#1011), **independent** of\n * the terminate fields: while the stream stays open, prune events\n * older than `now − keep` behind the closest safe snapshot via a\n * windowed close. Does not participate in the AND group or the `or`\n * block — a policy may terminate, prune, or both. Requires\n * `.snap(...)` earlier in the builder chain (type-gated) and a\n * window of at least one day — the close cycle is low-cadence\n * housekeeping, never sub-day realtime.\n */\nexport type AutoclosePolicy = z.infer<typeof AutoclosePolicySchema>;\n\n/** Compile a single `after` field into its predicate slice. @internal */\nfunction compile_after(\n after: NonNullable<AutoclosePolicy[\"after\"]>\n): AutoclosePredicate<Schemas> {\n return (_stream, head) => days_after(head.created, after.days) <= new Date();\n}\n\n/** Compile a single `is` field into its predicate slice. @internal */\nfunction compile_is(\n is: NonNullable<AutoclosePolicy[\"is\"]>\n): AutoclosePredicate<Schemas> {\n const set = new Set(typeof is === \"string\" ? [is] : is);\n return (_stream, head) => set.has(head.name as string);\n}\n\n/** Compile a single `reaches` field into its predicate slice. @internal */\nfunction compile_reaches(\n reaches: NonNullable<AutoclosePolicy[\"reaches\"]>\n): AutoclosePredicate<Schemas> {\n return (_stream, _head, count) => count >= reaches;\n}\n\n/**\n * Compile a declarative {@link AutoclosePolicy} into an\n * {@link AutoclosePredicate}. The state-builder's\n * `.autocloses({...})` overload calls this; tests can also build a\n * state and read `state.autoclose` to grab the compiled predicate.\n *\n * Returned predicate fires when either:\n *\n * 1. **All** top-level non-`or` fields match (AND), or\n * 2. **Any** field inside the `or` block matches.\n *\n * Top-level with zero non-`or` fields never satisfies path (1) — the\n * `every` check on an empty list is short-circuited to `false` so the\n * policy doesn't truncate the entire universe on an `or`-only\n * declaration. (Validation rejects all-empty bags up front; this guard\n * is the in-cycle equivalent for the synthesized empty AND-group.)\n *\n * Assignable to any `AutoclosePredicate<TEvents>` slot via\n * function-parameter contravariance — the returned predicate inspects\n * `head.name` as a plain string, so narrower event unions stay\n * assignable.\n *\n * Throws `ZodError` at call time when the options are invalid (empty\n * bag, non-positive `reaches`, sub-minute `after`, empty `is`, empty\n * `or`, nested `or`, unknown keys).\n *\n * @internal\n */\n/**\n * The smallest `after` window (in days) anywhere in a policy — across\n * the top-level `after` and the `or.after` block — or `undefined` when\n * the policy has no time component.\n *\n * The synthesized autoclose reaction (#1090) uses this to decide how to\n * wait: a policy with an `after` defers its re-check to `head.created`\n * plus this many days (the earliest its time gate could open); a policy\n * without one (`is` / `reaches` only) has no time gate, so the reaction\n * just waits for the next event to re-trigger rather than parking on a\n * due-time. Conservative — the min across branches never defers past\n * the soonest a branch could fire.\n *\n * @internal\n */\nexport function policy_min_after_days(\n options: AutoclosePolicy\n): number | undefined {\n const parsed = AutoclosePolicySchema.parse(options);\n const windows: number[] = [];\n if (parsed.after) windows.push(parsed.after.days);\n if (parsed.or?.after) windows.push(parsed.or.after.days);\n return windows.length ? Math.min(...windows) : undefined;\n}\n\n/**\n * The rolling-window width (in days) of a policy's `keep` field, or\n * `undefined` when the policy declares no rolling window. The\n * synthesized autoclose reaction prunes the prefix older than the\n * window (via a windowed close) and derives its prune due-time as\n * `tail.created` plus this many days — the earliest the oldest\n * surviving domain event can age out of the window.\n *\n * @internal\n */\nexport function policy_keep_days(options: AutoclosePolicy): number | undefined {\n const parsed = AutoclosePolicySchema.parse(options);\n return parsed.keep?.days;\n}\n\nexport function compile_autoclose_policy(\n options: AutoclosePolicy\n): AutoclosePredicate<Schemas> {\n const parsed = AutoclosePolicySchema.parse(options);\n\n // Top-level AND group — only the non-`or` fields.\n const and_preds: AutoclosePredicate<Schemas>[] = [];\n if (parsed.after) and_preds.push(compile_after(parsed.after));\n if (parsed.is) and_preds.push(compile_is(parsed.is));\n if (parsed.reaches) and_preds.push(compile_reaches(parsed.reaches));\n\n // OR-block — at least one of its fields must match.\n const or_preds: AutoclosePredicate<Schemas>[] = [];\n if (parsed.or) {\n if (parsed.or.after) or_preds.push(compile_after(parsed.or.after));\n if (parsed.or.is) or_preds.push(compile_is(parsed.or.is));\n if (parsed.or.reaches) or_preds.push(compile_reaches(parsed.or.reaches));\n }\n\n return (stream, head, count) => {\n // AND path: every top-level field matches AND the group is non-empty\n // (an `or`-only declaration leaves `and_preds` empty — that\n // shouldn't auto-fire).\n if (\n and_preds.length > 0 &&\n and_preds.every((p) => p(stream, head, count))\n ) {\n return true;\n }\n // OR path: any `or`-block field matches.\n if (or_preds.some((p) => p(stream, head, count))) {\n return true;\n }\n return false;\n };\n}\n","/**\n * @module autoclose-window\n * @category Internal\n *\n * Off-hours window math for autoclose — hour-in-zone, DST-gap handling, and\n * \"next time the window opens\". The autoclose **config** (defaults, schema,\n * resolver) lives in `./config.js`, the single home for builder-facing config\n * bags; this module is the runtime window logic those knobs drive.\n *\n * @internal\n */\n\nimport type { AutocloseConfig } from \"./config.js\";\n\n/**\n * The current hour `[0, 23]` in the given IANA time zone, DST-correct\n * via `Intl`. Split out so the window check can be unit-tested without\n * spinning a controller.\n *\n * @internal\n */\nexport function hour_in_zone(now: Date, timeZone: string): number {\n const parts = new Intl.DateTimeFormat(\"en-US\", {\n timeZone,\n hour: \"2-digit\",\n hourCycle: \"h23\",\n }).formatToParts(now);\n return Number(parts.find((p) => p.type === \"hour\")?.value);\n}\n\n/**\n * True when a plain `[start, end)` hour comparison places `hour` inside\n * the window. Half-open on hour boundaries and wrapping past midnight\n * when `start > end`.\n *\n * @internal\n */\nfunction hour_in_range(hour: number, start: number, end: number): boolean {\n return start < end\n ? hour >= start && hour < end\n : hour >= start || hour < end;\n}\n\n/**\n * True when `now` is the instant a DST spring-forward gap skipped over\n * the window's `start` hour. On such a day the local `start` hour never\n * occurs — the clock jumps from `start - 1` straight past `start` — so a\n * plain hour comparison would report the window closed all day. The gap\n * surfaces as a one-hour boundary where the local hour jumps from below\n * `start` to above it; that boundary instant is the window's replacement\n * opening. Detected by comparing the hour at `now` with the hour one\n * hour earlier: a jump of more than one hour that steps over `start`.\n *\n * @internal\n */\nfunction is_dst_gap_open(now: Date, timeZone: string, start: number): boolean {\n const hour = hour_in_zone(now, timeZone);\n if (hour <= start) return false;\n const prev = hour_in_zone(new Date(now.getTime() - 3_600_000), timeZone);\n // A normal step advances one local hour; a spring-forward gap advances\n // two, skipping exactly one local hour. This instant is the gap opening\n // only when the skipped hour is the window's `start`: the previous hour\n // sits just below `start` and this hour just above it.\n return prev === start - 1 && hour === start + 1;\n}\n\n/**\n * Whether `now` falls inside the configured off-hours window. The\n * window is half-open on hour boundaries — `[start, end)` — and wraps\n * past midnight when `start > end`. With no window configured every\n * tick runs, so callers treat `undefined` as \"always in window.\"\n *\n * On a DST spring-forward day whose `start` hour is skipped, the window\n * would otherwise be closed for the whole day (the `start` hour never\n * occurs). The gap's replacement instant is admitted so autoclose still\n * runs — see {@link is_dst_gap_open}.\n *\n * @internal\n */\nexport function in_autoclose_window(\n window: AutocloseConfig[\"autocloseWindow\"],\n now: Date\n): boolean {\n if (!window) return true;\n const hour = hour_in_zone(now, window.timeZone);\n return (\n hour_in_range(hour, window.start, window.end) ||\n is_dst_gap_open(now, window.timeZone, window.start)\n );\n}\n\n/**\n * The next instant the off-hours window opens at or after `now`. The\n * synthesized autoclose reaction defers to this when a tick lands\n * outside the window — parking until the window actually opens instead\n * of blind-polling on a configured cadence (the pre-#1175 behavior,\n * where a poll interval longer than the window could oscillate around\n * it and miss it repeatedly).\n *\n * Walks forward hour by hour and asks `Intl` for the local hour at each\n * step, so DST transitions resolve exactly the way the runtime's zone\n * database says they do — a 23- or 25-hour day never desynchronizes the\n * walk. The window validates as non-empty at build, and every zone hits\n * each `[0, 23]` hour label within any 48-hour span, so the walk always\n * terminates; the bound is a defensive backstop, with \"one day out\" as\n * the fallback no real zone can reach.\n *\n * Minute/second offsets within the opening hour are preserved from\n * `now` shifted by whole hours — the contract is hour-granular, matching\n * the window's own `[start, end)` hour semantics.\n *\n * On a DST spring-forward day whose `start` hour is skipped, the `start`\n * hour never occurs, so the minute-preserving walk would never match and\n * the window would defer ~24 h. The walk also checks each hour-aligned\n * boundary for the gap opening (see {@link is_dst_gap_open}) and returns\n * that boundary instant — deferring ~1 h to the replacement instant\n * rather than a full day. The boundary is returned as-is (no minute\n * offset): the gap opening is a single transition instant, not a range.\n *\n * @internal\n */\nexport function next_window_open(\n window: NonNullable<AutocloseConfig[\"autocloseWindow\"]>,\n now: Date\n): Date {\n const start_ms = now.getTime();\n for (let h = 0; h <= 48; h++) {\n const candidate = new Date(start_ms + h * 3_600_000);\n if (hour_in_zone(candidate, window.timeZone) === window.start)\n return candidate;\n // The `start` hour may be unreachable on a spring-forward day; catch\n // the gap boundary at the top of this candidate's hour.\n const boundary = new Date(\n candidate.getTime() - (candidate.getTime() % 3_600_000)\n );\n if (is_dst_gap_open(boundary, window.timeZone, window.start))\n return boundary;\n }\n return new Date(start_ms + 86_400_000);\n}\n","/**\n * @module close-signal\n * @category Internal\n *\n * The control-flow signal a reaction handler throws to *close* a stream\n * (#1090). Like {@link \"defer-signal\".DeferSignal} it rides the dispatcher's\n * `try/catch`, but where a defer holds the stream for later, a close asks the\n * orchestrator to retire it: `build_handle` turns the signal into a\n * `HandleResult.close` (a {@link CloseTarget}), `run_drain_cycle` acks the\n * triggering event and collects the target, and the `DrainController` hands it\n * to the orchestrator's `on_close` callback, which runs the same\n * `run_close_cycle` machinery as `app.close`.\n *\n * Internal: the compiled autoclose reaction throws it. Closing stays an\n * orchestrator capability — reactions only *signal* the intent, so the public\n * reaction-scoped `IAct` gains no `close`.\n *\n * The autoclose reaction runs on a **synthetic stream** (`source` = the\n * aggregate, `target` = a per-aggregate `__autoclose__` key) so it never\n * shares a watermark with the aggregate's own reactions. That makes the close\n * *target* distinct from the reaction's lease stream, so the signal carries the\n * stream to close explicitly (`stream`); when omitted (a user reaction closing\n * its own stream) it defaults to the lease stream.\n *\n * @internal\n */\nexport class CloseSignal extends Error {\n /**\n * Stream to close. Omitted → the reaction's own lease stream (a self-close).\n * The synthesized autoclose reaction sets it to the aggregate stream, since\n * its lease runs on a synthetic `__autoclose__` target.\n */\n readonly stream?: string;\n /** Optional archive callback to run while the stream is guarded. */\n readonly archive?: () => Promise<void>;\n /**\n * Watermark to ack the requesting reaction to before the close runs. The\n * close-cycle safety guard skips a stream whose subscriptions (matched by\n * source) lag the head; the autoclose reaction's `source` is the aggregate,\n * so it must advance its own watermark to the live head id it evaluated\n * against — otherwise it blocks its own close. Defaults to the triggering\n * event id when omitted.\n */\n readonly at?: number;\n /**\n * Windowed close (#1011): prune events older than this cutoff behind\n * the closest safe snapshot instead of retiring the stream. Thrown by\n * the autoclose reaction of a `.autocloses({ keep })` state; flows\n * into {@link CloseTarget.before}. Omitted → a full close.\n */\n readonly before?: Date;\n\n constructor(opts?: {\n stream?: string;\n archive?: () => Promise<void>;\n at?: number;\n before?: Date;\n }) {\n super(\"reaction requested close\");\n this.name = \"CloseSignal\";\n this.stream = opts?.stream;\n this.archive = opts?.archive;\n this.at = opts?.at;\n this.before = opts?.before;\n }\n}\n","/**\n * @module defer-signal\n * @category Internal\n *\n * The control-flow signal a reaction handler throws to *defer* itself\n * (#1090, #1091). Unlike an error, a defer is not a failure: the dispatcher\n * ({@link \"reactions\".build_handle}) catches it and produces a\n * `HandleResult.defer` — the triggering events stay pending (watermark not\n * advanced), `retry` is not bumped, and the drain re-visits the stream at the\n * resolved due-time.\n *\n * `DeferSignal` is the **imperative escape hatch** and is re-exported from the\n * package root, so reaction code can throw it directly when a static\n * `.defer(when)` step isn't expressive enough (a deadline computed from loaded\n * state, say). It carries the *unresolved* {@link DeferWhen}; the dispatcher\n * resolves it against the triggering event it is already dispatching (via\n * `resolve_defer_at`), which is what anchors `{ after }` and the `at` function\n * form to that event and keeps the due-time derivable. Fully dynamic times go\n * through `{ at: someDate }`.\n *\n * Modeled as an `Error` subclass — like `NonRetryableError` — so it rides the\n * existing `try/catch` in the handler loop instead of needing a separate\n * return channel through every dispatcher signature. The compiled autoclose\n * reaction throws the same signal.\n */\nimport type { DeferWhen } from \"../types/index.js\";\n\nexport class DeferSignal extends Error {\n /**\n * The unresolved schedule. The dispatcher turns this into an absolute\n * due-time by resolving it against the triggering event.\n */\n readonly when: DeferWhen;\n\n constructor(when: DeferWhen) {\n super(\"reaction deferred\");\n this.name = \"DeferSignal\";\n this.when = when;\n }\n}\n","/**\n * @module autoclose-reaction\n * @category Internal\n *\n * Synthesis of the online close-the-books reaction. `.autocloses(policy)`\n * is not a sweep: it is a reaction on every event the declaring state owns\n * that evaluates the policy against the LIVE head (so a reopened stream\n * re-evaluates correctly), defers to the cooldown's earliest opening\n * (`head.created + the policy's min after`), and closes via `CloseSignal`\n * once the policy holds.\n *\n * Runs at build time — after the registry is fully merged and before the\n * orchestrator classifies it — so the synthesized dynamic resolver is\n * discovered by `classify_registry` and its target stream subscribed. The\n * registry is complete once the builder finishes; the orchestrator never\n * mutates it.\n *\n * @internal\n */\n\nimport { SNAP_EVENT, store, TOMBSTONE_EVENT } from \"../ports.js\";\nimport type {\n Reaction,\n Registry,\n SchemaRegister,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport { days_after, days_before_now } from \"./autoclose-policy.js\";\nimport { in_autoclose_window, next_window_open } from \"./autoclose-window.js\";\nimport { CloseSignal } from \"./close-signal.js\";\nimport type { AutocloseConfig } from \"./config.js\";\nimport { DeferSignal } from \"./defer-signal.js\";\n\n/**\n * Prefix for the synthetic per-aggregate stream the autoclose reaction\n * runs on. `target = \\`${AUTOCLOSE_TARGET_PREFIX}${aggregate}\\``, `source =\n * aggregate` — a watermark distinct from the aggregate's own reactions, so\n * an autoclose defer never short-circuits them. Internal; not a public\n * surface.\n */\nexport const AUTOCLOSE_TARGET_PREFIX = \"__autoclose__:\";\n\n/**\n * Inject one synthesized autoclose reaction per `.autocloses(...)` state\n * into the registry's event registers. The handler resolves ports at call\n * time (`store()`), so the reaction is orchestrator-agnostic; the resolved\n * window/cadence config is captured here, at build.\n *\n * @internal\n */\nexport function synthesize_autoclose_reactions<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n registry: Registry<TSchemaReg, TEvents, TActions>,\n states: ReadonlyMap<string, State<any, any, any>>,\n config: AutocloseConfig\n): void {\n for (const st of states.values()) {\n const predicate = st.autoclose;\n if (!predicate) continue;\n const after_days = st.autoclose_after_days;\n const keep_days = st.autoclose_keep_days;\n const archiver = st.archive;\n const reaction: Reaction<TEvents> = {\n // Run on a SYNTHETIC stream — `source` is the aggregate, `target` is a\n // per-aggregate `__autoclose__` key — so the autoclose reaction never\n // shares a watermark with the aggregate's own reactions. A shared\n // watermark would let autoclose's defer short-circuit the aggregate's\n // other reactions (the \"a defer affects all reactions on a stream\"\n // hazard). The close still targets the aggregate (`source`).\n resolver: (e) => ({\n target: `${AUTOCLOSE_TARGET_PREFIX}${e.stream}`,\n source: e.stream,\n }),\n // Never block on autoclose: a transient query/store error should retry,\n // not quarantine the synthetic stream.\n options: { blockOnError: false, maxRetries: 3 },\n handler: async (event) => {\n const aggregate = event.stream;\n // Off-hours gating: outside the window, park until the window\n // opens. Derived from the window itself — no polling cadence.\n if (!in_autoclose_window(config.autocloseWindow, new Date()))\n throw new DeferSignal({\n at: next_window_open(config.autocloseWindow!, new Date()),\n });\n // Every policy keys on the *domain* head/count, so snapshots are\n // excluded unconditionally (#1356) — matching `scan_stream_heads` in\n // close-cycle.ts. `snap()` commits a `__snapshot__` at a higher id\n // right after the triggering domain event, so a terminal commit that\n // crosses a `.snap()` boundary would otherwise make the snapshot the\n // head: `is` never matches (`head.name === \"__snapshot__\"`) and never\n // recovers, `after` measures the cooldown from the snapshot's\n // timestamp, and `reaches:N` counts snapshot events toward N. Only\n // rolling-window (`keep`) policies additionally fetch the tail: the\n // prune decision keys on the oldest *domain* event — after a prune the\n // oldest surviving event is the boundary snapshot, whose age says\n // nothing about whether another prune would be productive.\n const stats = await store().query_stats([aggregate], {\n count: true,\n tail: keep_days !== undefined ? true : undefined,\n exclude: [TOMBSTONE_EVENT, SNAP_EVENT],\n });\n const entry = stats.get(aggregate);\n // No live (non-tombstone) head → already closed, nothing to do.\n if (!entry) return;\n const head = entry.head;\n // `count` is always present — query_stats is called with\n // `count: true` above, so the option contract guarantees it.\n if (predicate(aggregate, head, entry.count!))\n throw new CloseSignal({\n stream: aggregate,\n archive: archiver ? () => archiver(aggregate, head) : undefined,\n // Ack this reaction's own watermark to the live head so the\n // close-cycle guard (which matches subscriptions by source =\n // aggregate) sees it caught up instead of blocking its own close.\n at: head.id,\n });\n // Rolling window: when the oldest domain event has aged out of the\n // window, stage a windowed close — prune the prefix older than the\n // cutoff behind the closest safe snapshot. `tail` is present\n // whenever the stats entry is (same non-excluded event set).\n if (keep_days !== undefined) {\n const cutoff = days_before_now(keep_days);\n if (entry.tail!.created < cutoff)\n throw new CloseSignal({\n stream: aggregate,\n before: cutoff,\n archive: archiver\n ? () => archiver(aggregate, head, cutoff)\n : undefined,\n at: head.id,\n });\n }\n // Not eligible yet: park on the earliest derivable due-time — the\n // day the terminate cooldown opens and/or the day the oldest\n // domain event ages out of the rolling window. Neither → wait for\n // the next event to re-trigger (e.g. a `reaches` threshold).\n const dues: Date[] = [];\n if (after_days !== undefined)\n dues.push(days_after(head.created, after_days));\n if (keep_days !== undefined)\n dues.push(days_after(entry.tail!.created, keep_days));\n // Only defer to a FUTURE due-time. A due already in the past (the\n // stream idled longer than the cooldown while the AND-combined\n // predicate stayed unmet) can never be excluded by `claim`, which\n // skips only future `deferred_at` — so a past defer would be\n // re-claimed every cycle (perpetual query_stats burn, #1330). When\n // nothing is future, fall through and return: advance the watermark\n // and wait for the next event to re-trigger.\n const future = dues\n .map((d) => d.getTime())\n .filter((t) => t > Date.now());\n if (future.length)\n throw new DeferSignal({ at: new Date(Math.min(...future)) });\n },\n };\n const key = `__autoclose_${st.name}`;\n for (const event_name of Object.keys(st.events)) {\n registry.events[event_name as keyof TEvents]?.reactions.set(\n key,\n reaction as Reaction<TEvents, keyof TEvents>\n );\n }\n }\n}\n","/**\n * @module build-classify\n * @category Internal\n *\n * Build-time classification of the registry + state map. The Act constructor\n * needs four pre-computed inputs to wire its runtime subsystems:\n *\n * - `static_targets` — known-up-front reaction targets (statics get\n * subscribed once at init; dynamics scan per event)\n * - `has_dynamic_resolvers` — short-circuit flag for `correlate()`\n * - `reactive_events` — event names with at least one reaction (drives\n * the drain skip-flag in `do()` and `reset()`)\n * - `event_to_state` — event-name → owning state, for `close({restart})`\n * seed loading in multi-state apps\n *\n * Pure function — single pass over events + states, fully testable without\n * instantiating Act.\n *\n * @internal\n */\n\nimport type {\n Registry,\n Schema,\n SchemaRegister,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport type { StaticTarget } from \"./correlate-cycle.js\";\n\n/**\n * Classification result. Returned by {@link classify_registry}; consumed\n * piecewise by Act's constructor.\n *\n * @internal\n */\n/**\n * Sentinel for \"any reaction on this event has a dynamic resolver, so\n * the lane is opaque until correlate runs the function — arm every\n * controller.\" A Symbol rather than a string literal so it can't\n * collide with a user-declared lane named `\"all\"`.\n *\n * @internal\n */\nexport const ALL_LANES: unique symbol = Symbol(\"act-1103/all-lanes\");\n\n/**\n * Per-event lane fan-in (ACT-1103). For events whose every reaction\n * has a static resolver, the value is the union of those reactions'\n * declared lanes — `do()` arms only those controllers on commit. For\n * events with at least one dynamic resolver, the value is\n * {@link ALL_LANES}; `do()` falls back to arming every controller.\n *\n * @internal\n */\nexport type EventLaneSet = ReadonlySet<string> | typeof ALL_LANES;\n\nexport type Classification = {\n readonly static_targets: StaticTarget[];\n readonly has_dynamic_resolvers: boolean;\n readonly reactive_events: ReadonlySet<string>;\n readonly event_to_state: ReadonlyMap<string, State<any, any, any>>;\n readonly event_to_lanes: ReadonlyMap<string, EventLaneSet>;\n};\n\n/**\n * Walk the registry once to collect static reaction targets, the dynamic-\n * resolvers flag, the set of reactive event names, and the event-to-state\n * map. Static targets are deduplicated by (target, source) — two reactions\n * routing to the same projection produce one subscription.\n *\n * @internal\n */\nexport function classify_registry<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n registry: Registry<TSchemaReg, TEvents, TActions>,\n states: ReadonlyMap<string, State<Schema, any, any>>\n): Classification {\n const statics = new Map<string, StaticTarget>();\n // Per-target lane, checked across EVERY reaction to a target regardless of\n // source (#1325). A stream drains on exactly one lane, and `subscribe`\n // keys lane per-target with last-writer-wins semantics, so lane must agree\n // target-wide — the `(target, source)` scoping of `statics` is too narrow\n // to catch a same-target/different-source lane disagreement.\n const target_lanes = new Map<string, string | undefined>();\n const reactive_events = new Set<string>();\n const event_to_lanes = new Map<string, EventLaneSet>();\n let has_dynamic_resolvers = false;\n\n for (const [name, register] of Object.entries(registry.events)) {\n if (register.reactions.size > 0) reactive_events.add(name);\n for (const reaction of register.reactions.values()) {\n if (typeof reaction.resolver === \"function\") {\n has_dynamic_resolvers = true;\n // Dynamic resolver — lane is opaque until runtime. Mark the\n // event as wildcard so `do()` falls back to arming every\n // controller for any commit of it.\n event_to_lanes.set(name, ALL_LANES);\n } else {\n const { target, source, priority = 0, lane } = reaction.resolver;\n const lane_name = lane ?? \"default\";\n const existing_lanes = event_to_lanes.get(name);\n if (existing_lanes !== ALL_LANES) {\n const set =\n (existing_lanes as Set<string> | undefined) ?? new Set<string>();\n set.add(lane_name);\n event_to_lanes.set(name, set);\n }\n // ACT-1103 / #1325: lanes don't merge — any two reactions to the\n // same target must declare the same lane, regardless of source.\n // First reaction to a target records its lane; every later one must\n // match or it's a config error caught at build time.\n if (!target_lanes.has(target)) {\n target_lanes.set(target, lane);\n } else if (\n (target_lanes.get(target) ?? undefined) !== (lane ?? undefined)\n ) {\n throw new Error(\n `Stream \"${target}\" has conflicting lane assignments ` +\n `(\"${target_lanes.get(target) ?? \"default\"}\" vs \"${lane ?? \"default\"}\")`\n );\n }\n const key = `${target}|${source ?? \"\"}`;\n const existing = statics.get(key);\n if (!existing) {\n statics.set(key, { stream: target, source, priority, lane });\n } else if (priority > (existing.priority as number)) {\n // Multiple reactions with the same (target, source) — keep the max\n // priority so the highest-priority registrant sets the scheduling\n // priority (mirrors subscribe-side semantics). `existing.priority`\n // is always defined here since we always set it when inserting, but\n // the StaticTarget type marks it optional for external consumers.\n statics.set(key, { ...existing, priority });\n }\n }\n }\n }\n\n // Event-name → owning state. Duplicate event names are rejected at\n // registration time (merge.ts), so each entry is unambiguous.\n const event_to_state = new Map<string, State<any, any, any>>();\n for (const merged of states.values()) {\n for (const event_name of Object.keys(merged.events)) {\n event_to_state.set(event_name, merged);\n }\n }\n\n return {\n static_targets: [...statics.values()],\n has_dynamic_resolvers,\n reactive_events,\n event_to_state,\n event_to_lanes,\n };\n}\n","/**\n * @module internal/config\n * @category Internal\n *\n * **The single home for every builder-facing config bag in act-core.** Any\n * options object an operator hands to `act().build()`, a builder method\n * (`.on(...)`, `.do(...)`, `.withLane(...)`), or a runtime cycle\n * (`drain(...)` / `settle(...)`) is validated here with Zod — never with a\n * hand-written `if (x < min) throw` ladder — so misconfiguration surfaces as\n * a `ZodError` at the entry point, not as `NaN` arithmetic on the first cycle\n * tick.\n *\n * Layout: one section per bag, each with its `DEFAULT_*` constants, an\n * internal `<Type>OptionsSchema`, an inferred `<Type>Config`, and a\n * `resolve<Type>Config(options): <Type>Config`. The schema is never\n * re-exported — the public surface is the inferred type + resolver.\n *\n * Index of bags owned here:\n * - **Backoff** — retry pacing (`BackoffOptions`), nested in reaction/action.\n * - **Reaction** — `.do(handler, options)` (`blockOnError` / `maxRetries` / `backoff`).\n * - **Action** — `.on(entry, options)` (`maxRetries` / `backoff`).\n * - **Lane** — `.withLane({...})` (`leaseMillis` / `streamLimit` / `cycleMs`).\n * - **Drain / Settle** — `drain(...)` / `settle(...)` runtime knobs.\n * - **Autoclose** — the `.autocloses` / `ActOptions` autoclose knobs (+ window).\n * - **CircuitBreaker** — the store-op breaker on `ActOptions`.\n * - **Fold** — `projection(...).of(...)` batch-fold knobs.\n *\n * Sibling env/package config (`config()`, `NODE_ENV`, log level) lives in the\n * public `../config.ts` — a different concern (process environment, not\n * builder input). The `@rotorsoft/act-http` transport bags (`SseOptions`,\n * `OpenAPIOptions`) live in that package; core cannot own another package's\n * surface.\n *\n * Validation philosophy: reject only what is genuinely broken — `NaN`,\n * `±Infinity` (Zod 4's `z.number()` rejects both by default), and negatives\n * where nonsensical. A value that works today is never newly rejected. The\n * real strictness lands on `maxRetries` and `backoff`, the knobs whose bad\n * values silently corrupt the poison-quarantine and retry-loop-exit gates.\n *\n * @internal\n */\n\nimport { z } from \"zod\";\nimport type { ActOptions } from \"../act.js\";\nimport type {\n ActionOptions,\n BackoffOptions,\n DrainOptions,\n FoldOptions,\n LaneConfig,\n ReactionOptions,\n SettleOptions,\n} from \"../types/index.js\";\n\n// ---------------------------------------------------------------------------\n// Backoff — retry pacing. Nested inside the reaction/action bags below; also\n// resolvable on its own (`resolveBackoffConfig`) for direct callers.\n// ---------------------------------------------------------------------------\n\n/**\n * Rejects an off-union `strategy`, a non-finite/negative `baseMs`, or a\n * non-finite/non-positive `maxMs` (ACT-1269). Zod 4's `z.number()` rejects\n * `NaN`/`±Infinity` by default, so `.min(0)` / `.gt(0)` also close the\n * non-finite gap. No `maxMs >= baseMs` constraint — a sub-`baseMs` cap on\n * `exponential` is documented behavior, not an error.\n * @internal\n */\nconst BackoffOptionsSchema = z.object({\n strategy: z.enum([\"fixed\", \"linear\", \"exponential\"]),\n baseMs: z.number().min(0),\n maxMs: z.number().gt(0).optional(),\n jitter: z.boolean().optional(),\n});\n\n/** Validate a backoff bag, or pass `undefined` through. Throws `ZodError`. */\nexport function resolveBackoffConfig(\n options: BackoffOptions | undefined\n): BackoffOptions | undefined {\n return options === undefined\n ? undefined\n : BackoffOptionsSchema.parse(options);\n}\n\n// ---------------------------------------------------------------------------\n// Reaction — `.do(handler, options)`. `maxRetries` gates the poison-quarantine\n// decision (`retry >= maxRetries`), so a `NaN` here silently disables\n// `blockOnError` (a poison message retries forever). Validate the whole bag.\n// ---------------------------------------------------------------------------\n\nconst ReactionOptionsSchema = z.object({\n blockOnError: z.boolean(),\n maxRetries: z.number().int().min(0),\n backoff: BackoffOptionsSchema.optional(),\n});\n\n/** Resolved reaction options. */\nexport type ReactionConfig = z.infer<typeof ReactionOptionsSchema>;\n\n/** Validate a fully-defaulted reaction options bag. Throws `ZodError`. */\nexport function resolveReactionConfig(\n options: ReactionOptions\n): ReactionConfig {\n return ReactionOptionsSchema.parse(options);\n}\n\n// ---------------------------------------------------------------------------\n// Action — `.on(entry, options)`. `maxRetries` gates the command retry loop's\n// exit (`attempt >= maxRetries`), so a `NaN` here can spin the loop forever on\n// a contended stream. All fields optional (the argument itself is optional).\n// ---------------------------------------------------------------------------\n\nconst ActionOptionsSchema = z.object({\n maxRetries: z.number().int().min(0).optional(),\n backoff: BackoffOptionsSchema.optional(),\n});\n\n/** Resolved action options. */\nexport type ActionConfig = z.infer<typeof ActionOptionsSchema>;\n\n/** Validate an action options bag. Throws `ZodError`. */\nexport function resolveActionConfig(options: ActionOptions): ActionConfig {\n return ActionOptionsSchema.parse(options);\n}\n\n// ---------------------------------------------------------------------------\n// Lane — `.withLane({...})`. Per-lane overrides of the drain budget. Time\n// knobs (`leaseMillis` / `cycleMs`) accept any non-negative ms; `streamLimit`\n// is an integer count. Reject NaN/Infinity/negative; allow 0 (as today).\n// ---------------------------------------------------------------------------\n\nconst LaneConfigSchema = z.object({\n name: z.string().min(1),\n leaseMillis: z.number().min(0).optional(),\n streamLimit: z.number().int().min(0).optional(),\n cycleMs: z.number().min(0).optional(),\n});\n\n/** Validate a lane config. Throws `ZodError`. Returns the input shape. */\nexport function resolveLaneConfig<TName extends string>(\n options: LaneConfig<TName>\n): LaneConfig<TName> {\n LaneConfigSchema.parse(options);\n return options;\n}\n\n// ---------------------------------------------------------------------------\n// Drain / Settle — runtime knobs for `drain(...)` / `settle(...)`. Parsed once\n// per call (cheap). Reject NaN/Infinity/negative; allow 0. `correlate` is a\n// pass-through query filter (validated by the store), so it is not reshaped.\n// ---------------------------------------------------------------------------\n\nconst DrainOptionsSchema = z.object({\n streamLimit: z.number().int().min(0).optional(),\n eventLimit: z.number().int().min(0).optional(),\n leaseMillis: z.number().min(0).optional(),\n});\n\n/** Validate drain options, or pass `undefined` through. Throws `ZodError`. */\nexport function resolveDrainConfig(\n options: DrainOptions | undefined\n): DrainOptions | undefined {\n if (options === undefined) return undefined;\n DrainOptionsSchema.parse(options);\n return options;\n}\n\nconst SettleOptionsSchema = DrainOptionsSchema.extend({\n debounceMs: z.number().min(0).optional(),\n // `maxPasses` defaults to Infinity (no cap) when omitted; a present value is\n // a non-negative integer — `0` is legal and means \"run no passes\".\n maxPasses: z.number().int().min(0).optional(),\n}).loose();\n\n/** Validate settle options, or pass `undefined` through. Throws `ZodError`. */\nexport function resolveSettleConfig(\n options: SettleOptions | undefined\n): SettleOptions | undefined {\n if (options === undefined) return undefined;\n SettleOptionsSchema.parse(options);\n return options;\n}\n\n// ---------------------------------------------------------------------------\n// Act — the top-level `act().build(options)` scalar knobs. The nested bags\n// (`autocloseWindow`, `circuitBreaker`) are resolved by their own resolvers\n// below; the `scoped`/`correlator` fields are objects/functions passed\n// through untouched (`.loose()`), so only the scalar knobs are checked here.\n// ---------------------------------------------------------------------------\n\nconst ActOptionsSchema = z\n .object({\n maxSubscribedStreams: z.number().int().min(1).optional(),\n settleDebounceMs: z.number().int().min(0).optional(),\n })\n .loose();\n\n/** Validate the scalar `ActOptions` knobs at build. Throws `ZodError`. */\nexport function resolveActConfig(\n options: ActOptions | undefined\n): ActOptions | undefined {\n if (options === undefined) return undefined;\n ActOptionsSchema.parse(options);\n return options;\n}\n\n// ---------------------------------------------------------------------------\n// Autoclose — the autoclose knobs on `ActOptions` (+ the off-hours window).\n// The window *logic* (DST, hour math) stays in `autoclose-window.ts`; only\n// the schema, defaults, and resolver live here.\n// ---------------------------------------------------------------------------\n\n/**\n * @deprecated The cadence knob is derived from `autocloseWindow` now (#1175);\n * nothing consumes it. Kept for compat; removed in the next major.\n */\nexport const DEFAULT_AUTOCLOSE_CYCLE_MINUTES = 720;\n/** @deprecated Dead since #1090 removed the autoclose sweep. */\nexport const DEFAULT_CLOSE_BATCH_SIZE = 64;\n/** @deprecated Dead since #1090 removed the autoclose sweep. */\nexport const DEFAULT_CLOSE_YIELD_MS = 0;\n/** Default IANA zone for `autocloseWindow` when the operator omits one. */\nexport const DEFAULT_AUTOCLOSE_WINDOW_TZ = \"UTC\";\n\n/** True when `tz` is a zone the runtime's `Intl` accepts. @internal */\nfunction is_valid_time_zone(tz: string): boolean {\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: tz });\n return true;\n } catch {\n return false;\n }\n}\n\nconst AutocloseWindowSchema = z\n .object({\n start: z\n .number()\n .int()\n .min(0)\n .max(23, { message: \"autocloseWindow.start must be an hour in [0, 23]\" }),\n end: z\n .number()\n .int()\n .min(0)\n .max(23, { message: \"autocloseWindow.end must be an hour in [0, 23]\" }),\n timeZone: z\n .string()\n .refine(is_valid_time_zone, {\n message: \"autocloseWindow.timeZone must be a valid IANA time zone\",\n })\n .default(DEFAULT_AUTOCLOSE_WINDOW_TZ),\n })\n .refine((w) => w.start !== w.end, {\n message:\n \"autocloseWindow.start and end must differ — an empty window disables autoclose\",\n });\n\nconst AutocloseOptionsSchema = z.object({\n autocloseCycleMinutes: z\n .number()\n .int()\n .min(1)\n .max(1440)\n .default(DEFAULT_AUTOCLOSE_CYCLE_MINUTES),\n closeBatchSize: z\n .number()\n .int()\n .min(1)\n .max(1024)\n .default(DEFAULT_CLOSE_BATCH_SIZE),\n closeYieldMs: z.number().min(0).max(1000).default(DEFAULT_CLOSE_YIELD_MS),\n closeOnError: z.boolean().default(false),\n autocloseWindow: AutocloseWindowSchema.optional(),\n});\n\n/** Resolved autoclose configuration after validation + default expansion. */\nexport type AutocloseConfig = z.infer<typeof AutocloseOptionsSchema>;\n\n/** Validate + default the autoclose knobs on `ActOptions`. Throws `ZodError`. */\nexport function resolveAutocloseConfig(\n options: ActOptions | undefined\n): AutocloseConfig {\n return AutocloseOptionsSchema.parse({\n autocloseCycleMinutes: options?.autocloseCycleMinutes,\n closeBatchSize: options?.closeBatchSize,\n closeYieldMs: options?.closeYieldMs,\n closeOnError: options?.closeOnError,\n autocloseWindow: options?.autocloseWindow,\n });\n}\n\n// ---------------------------------------------------------------------------\n// CircuitBreaker — the store-op breaker on `ActOptions`. The `CircuitBreaker`\n// state machine stays in `circuit-breaker.ts` and imports the resolved type.\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_CIRCUIT_FAILURE_THRESHOLD = 5;\nexport const DEFAULT_CIRCUIT_COOLDOWN_MS = 30_000;\n\nconst CircuitBreakerOptionsSchema = z.object({\n failureThreshold: z\n .number()\n .int()\n .min(1)\n .default(DEFAULT_CIRCUIT_FAILURE_THRESHOLD),\n cooldownMs: z\n .number()\n .int()\n .min(100)\n .max(3_600_000)\n .default(DEFAULT_CIRCUIT_COOLDOWN_MS),\n});\n\n/** Public, all-optional circuit-breaker options bag for `act().build()`. */\nexport type CircuitBreakerOptions = z.input<typeof CircuitBreakerOptionsSchema>;\n\n/** Resolved circuit-breaker configuration. */\nexport type CircuitBreakerConfig = z.infer<typeof CircuitBreakerOptionsSchema>;\n\n/** Parse + apply defaults. Throws `ZodError` on out-of-range values. */\nexport const resolveCircuitBreakerConfig = (\n options?: CircuitBreakerOptions\n): CircuitBreakerConfig => CircuitBreakerOptionsSchema.parse(options ?? {});\n\n// ---------------------------------------------------------------------------\n// Fold — `projection(name).of(state)` batch-fold knobs.\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_FOLD_FLUSH_EVERY = 1_000;\nexport const DEFAULT_MAX_CACHED_STATES = 10_000;\n\nconst FoldOptionsSchema = z.object({\n flushEvery: z.number().int().min(1).default(DEFAULT_FOLD_FLUSH_EVERY),\n maxCachedStates: z.number().int().min(1).default(DEFAULT_MAX_CACHED_STATES),\n});\n\n/** Resolved fold configuration. */\nexport type FoldConfig = z.infer<typeof FoldOptionsSchema>;\n\n/** Validate + default the fold knobs. Throws `ZodError`. */\nexport function resolveFoldConfig(options: FoldOptions): FoldConfig {\n return FoldOptionsSchema.parse(options);\n}\n","/**\n * @module defer-config\n * @category Internal\n *\n * The `when` options for the public `defer` surface (#1091, RFC 0001). A\n * reaction defers itself to a future time either declaratively (the\n * `.defer(when)` builder step) or imperatively (`throw new DeferSignal(when)`\n * inside a handler); both resolve `when` through here.\n *\n * The load-bearing rule is **derivability**. A deferred stream's due-time must\n * be recomputable by whichever worker re-claims it after the wait, so `when`\n * never resolves against `Date.now()`. `after` is measured from the triggering\n * event's `created` timestamp, and `at` is either a fixed `Date` or a pure\n * function of the event. Either way, re-delivering the same event yields the\n * same due-time, which is what makes a defer correct across restarts and\n * competing workers.\n *\n * Validation follows the config-schema standard (CLAUDE.md): an internal\n * `*OptionsSchema` const, a public inferred type, and a resolver. Slice 2\n * ships `after` / `at`; recurrence (`every`) extends this in Slice 3 (#1092).\n *\n * @internal\n */\n\nimport { z } from \"zod\";\nimport type { Committed, DeferWhen, Schemas } from \"../types/index.js\";\nimport { DeferSignal } from \"./defer-signal.js\";\n\n/**\n * A relative span, measured from the triggering event's `created` time. At\n * least one field is required; fields are additive (`{ hours: 1, minutes: 30 }`\n * is 90 minutes).\n */\nconst DeferDurationSchema = z\n .object({\n days: z.number().positive().optional(),\n hours: z.number().positive().optional(),\n minutes: z.number().positive().optional(),\n })\n .strict()\n .refine((d) => d.days != null || d.hours != null || d.minutes != null, {\n message: \"defer: a duration needs at least one of days, hours, or minutes\",\n });\n\n/**\n * Zod schema for the `defer(when)` options bag. Exactly one of `after` / `at`;\n * `at` is an absolute `Date`. Internal per the config standard; the public\n * surface is {@link DeferWhen} and {@link resolve_defer_at}.\n *\n * @internal\n */\nconst DeferWhenSchema = z\n .object({\n after: DeferDurationSchema.optional(),\n at: z.date().optional(),\n })\n .strict()\n .refine((w) => (w.after === undefined) !== (w.at === undefined), {\n message: \"defer: specify exactly one of `after` or `at`\",\n });\n\n/** Sum a duration bag to milliseconds. @internal */\nfunction duration_ms(d: {\n days?: number;\n hours?: number;\n minutes?: number;\n}): number {\n return (\n (d.days ?? 0) * 86_400_000 +\n (d.hours ?? 0) * 3_600_000 +\n (d.minutes ?? 0) * 60_000\n );\n}\n\n/**\n * Resolve `when` to an absolute due-time (ms since epoch) for a given\n * triggering event. Validates via {@link DeferWhenSchema} (throws `ZodError`\n * on a bad shape), then derives the time: `after` from `event.created`, `at`\n * from its absolute `Date`. Never reads `Date.now()`, so the result is stable\n * across re-delivery.\n *\n * @internal\n */\nexport function resolve_defer_at<E extends Schemas>(\n when: DeferWhen,\n event: Committed<E, keyof E>\n): number {\n const parsed = DeferWhenSchema.parse(when);\n if (parsed.after) return event.created.getTime() + duration_ms(parsed.after);\n return parsed.at!.getTime();\n}\n\n/**\n * The schedule handed to the declarative `.defer` builder step: either a\n * literal {@link DeferWhen} (fixed cooldown/deadline) or a function of the\n * triggering event (read the payload to choose the schedule).\n *\n * @internal\n */\nexport type DeferSchedule<TEvent> = DeferWhen | ((event: TEvent) => DeferWhen);\n\n/**\n * Validate a literal `when` at build time (fail fast, per the config-schema\n * standard) — throws `ZodError` on a bad shape (both/neither of `after`/`at`,\n * an empty or non-positive duration). The function form of a `.defer` schedule\n * can only be checked when it runs, so builders pass just the literal here.\n *\n * @internal\n */\nexport function assert_defer_when(when: DeferWhen): void {\n DeferWhenSchema.parse(when);\n}\n\n/**\n * Wrap a reaction handler so it holds until its schedule is due, then runs.\n * On each delivery it resolves the schedule against the triggering event; if\n * the due-time hasn't arrived it throws {@link DeferSignal} (the drain holds\n * the stream, no watermark advance, no retry bump), otherwise it runs the\n * real handler. The wrapper keeps the original handler's `name` so reaction\n * registration and de-dup are unaffected, and preserves the handler's exact\n * type so the builder step is transparent.\n *\n * @internal\n */\nexport function make_deferred<H extends (...args: any[]) => Promise<unknown>>(\n handler: H,\n schedule: DeferSchedule<Parameters<H>[0]>\n): H {\n const call = handler as (...args: unknown[]) => Promise<unknown>;\n const deferred = async (\n event: Parameters<H>[0],\n stream: string,\n app: unknown\n ) => {\n const when = typeof schedule === \"function\" ? schedule(event) : schedule;\n if (Date.now() < resolve_defer_at(when, event)) throw new DeferSignal(when);\n return call(event, stream, app);\n };\n Object.defineProperty(deferred, \"name\", { value: handler.name });\n return deferred as unknown as H;\n}\n","/**\n * @module merge\n * @category Internal\n *\n * Shared utilities for merging partial states and projections across builders.\n * Lives in `internal/` because the symbols are consumed by the builder layer\n * (`act-builder`, `slice-builder`, `projection-builder`) but aren't part of\n * the public package surface.\n *\n * @internal\n */\nimport { ZodObject, type ZodType } from \"zod\";\nimport type { Projection } from \"../builders/projection-builder.js\";\nimport type { Schema, State } from \"../types/index.js\";\n\n/**\n * Unwraps wrapper types (ZodOptional, ZodNullable, ZodDefault, ZodReadonly)\n * to find the base type name, e.g. `z.string().optional()` -> `\"ZodString\"`.\n */\nfunction base_type_name(zodType: ZodType): string {\n let t: any = zodType;\n while (typeof t.unwrap === \"function\") {\n t = t.unwrap();\n }\n return t.constructor.name;\n}\n\n/**\n * Merges two Zod schemas. If both are ZodObject instances, checks for\n * overlapping shape keys with incompatible base types (throws descriptive\n * error), then merges via `.extend()`. Falls back to keeping existing\n * schema if either is not a ZodObject.\n */\nfunction merge_schemas(\n existing: ZodType,\n incoming: ZodType,\n state_name: string\n): ZodType {\n if (existing instanceof ZodObject && incoming instanceof ZodObject) {\n const existing_shape = existing.shape as Record<string, ZodType>;\n const incoming_shape = incoming.shape as Record<string, ZodType>;\n for (const key of Object.keys(incoming_shape)) {\n if (key in existing_shape) {\n const existing_base = base_type_name(existing_shape[key]);\n const incoming_base = base_type_name(incoming_shape[key]);\n if (existing_base !== incoming_base) {\n throw new Error(\n `Schema conflict in \"${state_name}\": key \"${key}\" has type \"${existing_base}\" but incoming partial declares \"${incoming_base}\"`\n );\n }\n }\n }\n return existing.extend(incoming_shape);\n }\n return existing;\n}\n\n/**\n * Merges two init functions by spreading both results together.\n * Each partial only provides its own defaults.\n */\nfunction merge_inits<TState extends Schema>(\n existing: () => Readonly<TState>,\n incoming: () => Readonly<TState>\n): () => Readonly<TState> {\n return () => ({ ...existing(), ...incoming() });\n}\n\n/**\n * Registers a state into a states map and action/event registries,\n * merging with existing same-name states (partial state support).\n */\nexport function register_state(\n state: State<any, any, any>,\n states: Map<string, State<any, any, any>>,\n actions: Record<string, any>,\n events: Record<string, any>\n): void {\n const existing = states.get(state.name);\n if (existing) {\n merge_into_existing(state, existing, states, actions, events);\n } else {\n register_new_state(state, states, actions, events);\n }\n}\n\n/**\n * Registers a state for the first time. All action/event names must be unique\n * across the registry; collisions throw.\n */\nfunction register_new_state(\n state: State<any, any, any>,\n states: Map<string, State<any, any, any>>,\n actions: Record<string, any>,\n events: Record<string, any>\n): void {\n states.set(state.name, state);\n for (const name of Object.keys(state.actions)) {\n if (actions[name]) throw new Error(`Duplicate action \"${name}\"`);\n actions[name] = state;\n }\n for (const name of Object.keys(state.events)) {\n if (events[name]) throw new Error(`Duplicate event \"${name}\"`);\n events[name] = { schema: state.events[name], reactions: new Map() };\n }\n}\n\n/**\n * Merges an incoming partial state into an existing same-name state and\n * updates the action/event registries. Splits into four phases:\n * 1. validate no cross-state action/event collisions\n * 2. merge per-event patches (one custom patch per event)\n * 3. build the merged state and replace it in the states map\n * 4. update action→state pointers and register new events\n */\nfunction merge_into_existing(\n state: State<any, any, any>,\n existing: State<any, any, any>,\n states: Map<string, State<any, any, any>>,\n actions: Record<string, any>,\n events: Record<string, any>\n): void {\n // 1. Validate no cross-state collisions for actions/events\n for (const name of Object.keys(state.actions)) {\n // Same schema reference means the same partial re-registered via another slice\n if (existing.actions[name] === state.actions[name]) continue;\n if (actions[name]) throw new Error(`Duplicate action \"${name}\"`);\n }\n for (const name of Object.keys(state.events)) {\n // Same schema reference means the same partial re-registered via another slice\n if (existing.events[name] === state.events[name]) continue;\n // Same event name registered in a same-name state partial with a\n // different Zod schema reference — silent contract drift that the\n // type system can't catch (structurally compatible shapes flow\n // through TS even when refinements/enums/literals disagree).\n // Reference identity is the rule: cross-slice event schemas must\n // come from a single shared instance.\n if (existing.events[name]) {\n throw new Error(\n `Event \"${name}\" in state \"${state.name}\" is declared with different Zod schemas across slices. ` +\n `Cross-slice event schemas must reference the same instance — ` +\n `extract a shared schema (e.g. \\`export const ${name} = z.object({ ... })\\` in a shared module) ` +\n `and import it in every slice that declares it.`\n );\n }\n if (events[name]) throw new Error(`Duplicate event \"${name}\"`);\n }\n\n // 2. Merge patches with custom-vs-passthrough resolution\n const merged_patch = merge_patches(existing.patch, state.patch, state.name);\n\n // 3. Build merged state\n const merged = {\n ...existing,\n state: merge_schemas(existing.state, state.state, state.name),\n init: merge_inits(existing.init, state.init),\n events: { ...existing.events, ...state.events },\n actions: { ...existing.actions, ...state.actions },\n patch: merged_patch,\n on: { ...existing.on, ...state.on },\n given: { ...existing.given, ...state.given },\n snap:\n state.snap && existing.snap && state.snap !== existing.snap\n ? (() => {\n throw new Error(\n `Duplicate snap strategy for state \"${state.name}\"`\n );\n })()\n : state.snap || existing.snap,\n };\n states.set(state.name, merged);\n\n // 4. Update action→state pointers; register events not yet seen\n for (const name of Object.keys(merged.actions)) {\n actions[name] = merged;\n }\n for (const name of Object.keys(state.events)) {\n if (events[name]) continue; // already registered, preserve reactions\n events[name] = { schema: state.events[name], reactions: new Map() };\n }\n}\n\n/**\n * Merges two patch maps. Only one custom (non-passthrough) patch per event is\n * allowed; passthroughs always yield to custom reducers, and re-registering\n * the same custom patch (same reference, e.g. across slices) is a no-op.\n */\nfunction merge_patches(\n existing: Record<string, any>,\n incoming: Record<string, any>,\n state_name: string\n): Record<string, any> {\n const merged = { ...existing };\n for (const name of Object.keys(incoming)) {\n const existing_p = existing[name];\n const incoming_p = incoming[name];\n if (!existing_p) {\n merged[name] = incoming_p;\n continue;\n }\n const existing_is_default = existing_p._passthrough;\n const incoming_is_default = incoming_p._passthrough;\n if (\n !existing_is_default &&\n !incoming_is_default &&\n existing_p !== incoming_p\n ) {\n throw new Error(\n `Duplicate custom patch for event \"${name}\" in state \"${state_name}\"`\n );\n }\n // Keep whichever is custom; if both passthrough or existing custom, keep existing\n if (existing_is_default && !incoming_is_default) {\n merged[name] = incoming_p;\n }\n }\n return merged;\n}\n\n/**\n * Merges reactions from one event register into another. The target is\n * assumed to already contain entries for every event name in the source\n * (e.g., act-builder's `.withSlice()` registers the slice's states first,\n * which seeds the target events). Reactions are keyed by `handler.name`;\n * two distinct handlers sharing a name on the same event throw rather than\n * silently overwriting (ACT-979). Re-merging the identical reaction object\n * is idempotent — mirrors {@link register_batch_handler}.\n */\nexport function merge_event_register(\n target: Record<string, { reactions: Map<string, unknown> }>,\n source: Record<string, { reactions: Map<string, unknown> }>\n): void {\n for (const [event_name, source_reg] of Object.entries(source)) {\n const target_reg = target[event_name];\n if (!target_reg) continue;\n for (const [name, reaction] of source_reg.reactions) {\n const existing = target_reg.reactions.get(name);\n if (existing !== undefined && existing !== reaction)\n throw new Error(\n `Duplicate reaction \"${name}\" for event \"${event_name}\". ` +\n `Reaction handlers are keyed by function name; rename one of them.`\n );\n target_reg.reactions.set(name, reaction);\n }\n }\n}\n\n/**\n * Merges a projection's event schemas and reactions into an event registry,\n * deduplicating reaction names by appending \"_p\" on collision.\n */\nexport function merge_projection(\n proj: Projection<any>,\n events: Record<string, any>\n): void {\n for (const event_name of Object.keys(proj.events)) {\n const proj_register = proj.events[event_name];\n const existing = events[event_name];\n if (!existing) {\n events[event_name] = {\n schema: proj_register.schema,\n reactions: new Map(proj_register.reactions),\n };\n } else {\n for (const [name, reaction] of proj_register.reactions) {\n // The `_p` rename resolves a NAME collision between two genuinely\n // different handlers. Registering the SAME reaction object again is\n // not a collision — it is the same projection reached along two\n // paths (exported from a module and embedded by two slices, or a\n // `.withProjection(p)` written twice) — and renaming it registered a\n // second copy under `name_p`, so the handler ran twice per event,\n // forever, frozen into the registry at build (#1439).\n //\n // Not the at-least-once redelivery contract: a structural duplicate,\n // deterministic on every event, with no signal anywhere. Both\n // siblings already guard on identity — `merge_event_register` throws\n // on a different handler under the same name, `register_batch_handler`\n // likewise — this one only lacked the check.\n if ([...existing.reactions.values()].includes(reaction)) continue;\n let key = name;\n while (existing.reactions.has(key)) key = `${key}_p`;\n existing.reactions.set(key, reaction);\n }\n }\n }\n}\n\n// Resolves the event stream as source and target (default)\nexport const _this_ = ({ stream }: { stream: string }) => ({\n source: stream,\n target: stream,\n});\n","/**\n * @module builder-utils\n * @category Internal\n *\n * Shared builder machinery reused by both `act-builder.ts` and\n * `slice-builder.ts`. The two builders expose the same reaction-registration\n * and lane-declaration surface and differ only in the concrete builder type\n * they return (`ActBuilder` vs `SliceBuilder`) and the event register they\n * write into (`registry.events` vs the slice's `events`). This module owns the\n * one copy of that logic so the builders stay thin delegations.\n *\n * @internal\n */\n\nimport { DEFAULT_LANE } from \"../ports.js\";\nimport type {\n Committed,\n EventRegister,\n LaneConfig,\n Reaction,\n ReactionHandler,\n ReactionOptions,\n ReactionResolver,\n Schemas,\n} from \"../types/index.js\";\nimport { resolveReactionConfig } from \"./config.js\";\nimport {\n assert_defer_when,\n type DeferSchedule,\n make_deferred,\n} from \"./defer-config.js\";\nimport { _this_ } from \"./merge.js\";\n\n/**\n * Validate and register a drain lane (ACT-1103): the `\"default\"` name is\n * reserved and each lane name must be unique. Mutates `lanes` in place; the\n * caller returns its own builder for chaining.\n *\n * @internal\n */\nexport function register_lane(config: LaneConfig, lanes: LaneConfig[]): void {\n if (config.name === DEFAULT_LANE)\n throw new Error(`Lane \"${DEFAULT_LANE}\" is reserved`);\n if (lanes.some((l) => l.name === config.name))\n throw new Error(`Lane \"${config.name}\" was already declared`);\n lanes.push(config);\n}\n\n/**\n * Build the `.on(event)` step shared by both builders. Registers a reaction\n * (named-function + duplicate guards, fail-fast literal-schedule validation,\n * the default `_this_` resolver, and the `.defer` handler wrap) into\n * `events[event].reactions`, and hands back `builder` patched with `.to(...)`\n * for in-place resolver routing.\n *\n * The strict, builder-specific type is supplied by each builder's own `on`\n * signature ({@link ReactionOn}); the runtime here is builder-agnostic.\n *\n * @internal\n */\nexport function reaction_on<\n TEvents extends Schemas,\n TKey extends keyof TEvents,\n TBuilder,\n>(event: TKey, events: EventRegister<TEvents>, builder: TBuilder) {\n const register = (\n handler: ReactionHandler<TEvents, TKey>,\n options?: Partial<ReactionOptions>,\n schedule?: DeferSchedule<Committed<TEvents, TKey>>\n ) => {\n if (!handler.name)\n throw new Error(\n `Reaction handler for \"${String(event)}\" must be a named function`\n );\n if (events[event].reactions.has(handler.name))\n throw new Error(\n `Duplicate reaction \"${handler.name}\" for event \"${String(event)}\". ` +\n `Reaction handlers are keyed by function name; rename one of them.`\n );\n // Fail fast on a bad literal schedule; the function form is checked when it\n // runs (no event to resolve against at build time).\n if (schedule && typeof schedule !== \"function\") assert_defer_when(schedule);\n const reaction: Reaction<TEvents, TKey> = {\n handler: schedule ? make_deferred(handler, schedule) : handler,\n resolver: _this_,\n // #1269: validate the whole bag at the declaration site so a bad\n // `maxRetries`/`backoff`/`blockOnError` throws ZodError at build,\n // not a NaN gate on the first retry.\n options: resolveReactionConfig({\n blockOnError: options?.blockOnError ?? true,\n maxRetries: options?.maxRetries ?? 3,\n backoff: options?.backoff,\n }),\n };\n // Register once with the default _this_ resolver. If `.to()` is chained\n // next, it patches the same reaction's resolver in place — no second\n // Map.set() round-trip.\n events[event].reactions.set(handler.name, reaction);\n return Object.assign(builder as object, {\n to(resolver: ReactionResolver<TEvents, TKey> | string) {\n reaction.resolver =\n typeof resolver === \"string\" ? { target: resolver } : resolver;\n return builder;\n },\n });\n };\n return {\n do: (\n handler: ReactionHandler<TEvents, TKey>,\n options?: Partial<ReactionOptions>\n ) => register(handler, options),\n defer: (schedule: DeferSchedule<Committed<TEvents, TKey>>) => ({\n do: (\n handler: ReactionHandler<TEvents, TKey>,\n options?: Partial<ReactionOptions>\n ) => register(handler, options, schedule),\n }),\n };\n}\n","/**\n * @module internal/circuit-breaker\n *\n * Orchestrator-level circuit breaker for store operations. The drain loop\n * polls `claim()` continuously; when the backing store goes down every poll\n * throws a {@link StoreError}, and without a breaker the orchestrator would\n * spin at the cycle cadence hammering a dead database and flooding the logs.\n *\n * The breaker collapses that into three states:\n *\n * - **closed** — normal operation; failures are counted.\n * - **open** — `failureThreshold` consecutive failures tripped it; attempts\n * are skipped for `cooldownMs` so the store gets room to recover.\n * - **half-open** — the cooldown elapsed; a single trial attempt is allowed.\n * Success closes the breaker; failure re-opens it and restarts the clock.\n *\n * Time is passed in (`now`) rather than read from the clock so the state\n * machine is deterministic under test.\n */\n\nimport type { CircuitBreakerConfig } from \"./config.js\";\n\n/** Circuit breaker state. */\nexport type CircuitState = \"closed\" | \"open\" | \"half-open\";\n\n// The circuit-breaker config schema, defaults, and resolver live in\n// `./config.js` (the single home for builder-facing config bags). This\n// module keeps only the state machine that consumes the resolved config.\n\n/**\n * Side-effect hooks the orchestrator wires into the breaker so consumers\n * (drain / settle / autoclose) don't each thread their own callbacks.\n */\nexport type CircuitBreakerHooks = {\n /** Invoked on every {@link CircuitBreaker.failed} with the error and state. */\n readonly on_error?: (error: unknown, circuit: CircuitState) => void;\n /**\n * Invoked once, `cooldownMs` after the breaker opens (and again on each\n * re-open). The orchestrator wires it to re-attempt a drain — so recovery\n * is automatic even on the default lane, which has no periodic poller.\n */\n readonly on_retry?: () => void;\n};\n\nexport class CircuitBreaker {\n private _failures = 0;\n private _opened_at: number | undefined;\n private _wake: ReturnType<typeof setTimeout> | undefined;\n private readonly _threshold: number;\n private readonly _cooldown_ms: number;\n private readonly _hooks: CircuitBreakerHooks;\n\n constructor(config: CircuitBreakerConfig, hooks: CircuitBreakerHooks = {}) {\n this._threshold = config.failureThreshold;\n this._cooldown_ms = config.cooldownMs;\n this._hooks = hooks;\n }\n\n /** Current state given the wall-clock `now`. */\n state(now: number): CircuitState {\n if (this._opened_at === undefined) return \"closed\";\n return now - this._opened_at >= this._cooldown_ms ? \"half-open\" : \"open\";\n }\n\n /** A store op passed — reset to closed and cancel any pending retry. */\n passed(): void {\n this._failures = 0;\n this._opened_at = undefined;\n this._clear_wake();\n }\n\n /**\n * A store op failed. Opens the breaker when the consecutive-failure\n * threshold is reached, or immediately re-opens (restarting the cooldown)\n * if a half-open trial just failed. Returns the resulting state.\n *\n * Callers gate on the state directly — `state(now) === \"open\"` means skip.\n * On opening, schedules the `on_retry` wake so recovery is automatic;\n * always surfaces the failure via `on_error`.\n */\n failed(now: number, error?: unknown): CircuitState {\n const circuit = this._advance(now);\n if (circuit === \"open\") this._schedule_wake();\n this._hooks.on_error?.(error, circuit);\n return circuit;\n }\n\n /** Cancel the pending retry timer. Idempotent; call on shutdown. */\n stop(): void {\n this._clear_wake();\n }\n\n /**\n * Schedule the `on_retry` wake `cooldownMs` out so the breaker re-trials\n * the store on its own. No-op when no `on_retry` hook is wired (e.g. unit\n * tests of the pure state machine). The timer is `unref`'d so it never\n * keeps the process alive.\n */\n private _schedule_wake(): void {\n if (!this._hooks.on_retry) return;\n this._clear_wake();\n this._wake = setTimeout(() => {\n this._wake = undefined;\n this._hooks.on_retry?.();\n }, this._cooldown_ms);\n this._wake.unref();\n }\n\n private _clear_wake(): void {\n if (this._wake) {\n clearTimeout(this._wake);\n this._wake = undefined;\n }\n }\n\n /** Pure state transition for a failure — no side effects. */\n private _advance(now: number): CircuitState {\n // Already tripped: this can only be reached from a half-open trial\n // (open skips attempts), so the trial failed — re-open and restart.\n if (this._opened_at !== undefined) {\n this._opened_at = now;\n return \"open\";\n }\n this._failures += 1;\n if (this._failures >= this._threshold) {\n this._opened_at = now;\n return \"open\";\n }\n return \"closed\";\n }\n}\n","/**\n * @module close-cycle\n * @category Internal\n *\n * Pure orchestration of the close-the-books flow: scan stream heads,\n * partition by reaction safety, guard with tombstones, optionally seed\n * restart state, run user archive callbacks, atomically truncate, and\n * update the cache.\n *\n * The Act orchestrator owns lifecycle (correlate gate, emit(\"closed\")) and\n * the registry-derived inputs (reactive-event count, event→state map). All\n * sequential phase work between those state touches lives here.\n *\n * @internal\n */\n\nimport { cache, SNAP_EVENT, store, TOMBSTONE_EVENT } from \"../ports.js\";\nimport type {\n CloseResult,\n CloseTarget,\n Logger,\n Schema,\n State,\n} from \"../types/index.js\";\nimport type { EsOps } from \"./event-sourcing.js\";\n\n/**\n * Dependencies the close cycle needs from the Act orchestrator. Decoupled\n * from `Act` itself so the cycle can be exercised from tests in isolation.\n *\n * @internal\n */\nexport type CloseCycleDeps = {\n readonly reactive_events_size: number;\n readonly event_to_state: ReadonlyMap<string, State<any, any, any>>;\n readonly load: EsOps[\"load\"];\n readonly tombstone: EsOps[\"tombstone\"];\n readonly logger: Logger;\n /**\n * Correlation id for the close transaction. Caller (`Act.close`)\n * computes this via the configured {@link Correlator}, so close\n * commits share the user's chosen id scheme instead of stamping a\n * UUID.\n */\n readonly correlation: string;\n /**\n * Page size for the safety probe's `query_streams` pagination.\n * Defaults to {@link SAFETY_PROBE_PAGE_SIZE}; production callers omit\n * it, tests set a small value to exercise the multi-page path.\n */\n readonly probe_page_size?: number;\n /**\n * Per-stream critical section (#1222). The windowed branch is\n * deliberately guard-free at the store level — a past cutoff makes the\n * boundary immutable, so a concurrent append can never race the prune.\n * But that assumes a *single* closer per stream. A manual\n * `app.close([{stream, before}])` runs `run_close_cycle` directly,\n * bypassing the `__autoclose__:X` lease that would otherwise exclude a\n * concurrent autoclose windowed close, so both closers can archive the\n * same prefix — a double S3 upload / double JSONL append. This runs the\n * given work under a process-local per-stream lock so the two closers\n * serialize; the second sees the already-pruned prefix and skips its\n * archive. Provided by the Act orchestrator (shared across `app.close`\n * and the drain's `on_close`); defaults to identity (no serialization)\n * when the cycle is exercised in isolation.\n */\n readonly with_stream_lock?: <T>(\n stream: string,\n work: () => Promise<T>\n ) => Promise<T>;\n};\n\n/**\n * Page size for the safety probe's keyset pagination over the\n * subscriptions table. Above `query_streams`'s default `limit` of 100\n * to keep the round-trip count low while bounding per-page work.\n *\n * @internal\n */\nexport const SAFETY_PROBE_PAGE_SIZE = 1000;\n\n/**\n * Per-stream scan result: latest non-tombstone domain event metadata.\n * `last_event_name` is always defined — the scan filters tombstones in the\n * callback and queries without `with_snaps`, so any event reaching the\n * callback is a domain event whose name we capture alongside id/version.\n */\ntype StreamHead = {\n readonly max_id: number;\n readonly version: number;\n readonly last_event_name: string;\n /**\n * Set when the stream already carries a tombstone but still holds domain\n * events — a close that wrote its guard and was then interrupted before\n * truncating (a throwing archive callback, or a `truncate` that failed).\n * Carries the existing guard's event id so the retry resumes at Phase 4\n * instead of re-tombstoning (which would fail the version guard) or being\n * dropped from the scan entirely (#1389).\n */\n readonly resumed_guard?: { readonly id: number };\n};\n\n/**\n * Run the full close cycle for the given targets. Caller owns the\n * lifecycle event emission.\n *\n * Targets carrying a `before` cutoff take the **windowed** branch — a\n * pure prefix delete behind an existing snapshot (see\n * {@link run_windowed_closes}); the rest run the guarded\n * tombstone/restart pipeline below.\n *\n * @internal\n */\nexport async function run_close_cycle(\n targets: CloseTarget[],\n deps: CloseCycleDeps\n): Promise<CloseResult> {\n // Caller (Act.close) filters empty targets; run_close_cycle assumes at\n // least one target.\n const target_map = new Map(targets.map((t) => [t.stream, t]));\n for (const t of target_map.values()) {\n if (t.before !== undefined && t.restart)\n throw new Error(\n `close: \\`before\\` and \\`restart\\` are mutually exclusive (stream \"${t.stream}\") — a windowed close keeps the stream live behind a real snapshot; restart reseeds it`\n );\n }\n const windowed = [...target_map.values()].filter(\n (t) => t.before !== undefined\n );\n const full = [...target_map.values()].filter((t) => t.before === undefined);\n const skipped: string[] = [];\n const windowed_result = windowed.length\n ? await run_windowed_closes(windowed, deps, skipped)\n : new Map();\n if (!full.length) return { truncated: windowed_result, skipped };\n const streams = full.map((t) => t.stream);\n\n // 1. Scan: find the latest non-tombstone event per stream\n const stream_info = await scan_stream_heads(streams);\n\n // 1b. Reject restart targets whose owning state carries sensitive\n // fields, BEFORE anything is written. The seed load in phase 4 is\n // actorless, so every `sensitive()` field would fold to the redaction\n // sentinel and the truncate would then delete the originals — and\n // loading privileged instead would persist plaintext into\n // `__snapshot__.data`, which `forget_pii` cannot reach (the reason\n // `.snap()` is rejected at build time for these states). Such a stream\n // cannot be restarted at all, so it must not be closed either: the\n // caller asked to keep the aggregate alive, and tombstoning it instead\n // would be a strictly more destructive outcome than the one requested.\n // It lands in `skipped`, the established channel for \"couldn't do this\n // one\", with nothing mutated.\n for (const target of full) {\n if (!target.restart) continue;\n const info = stream_info.get(target.stream);\n if (!info) continue;\n const owner = deps.event_to_state.get(info.last_event_name);\n if (owner?.pii_aware) {\n deps.logger.error(\n `Refusing to close \"${target.stream}\" with restart: state \"${owner.name}\" carries sensitive fields, so a restart seed would persist redacted values while deleting the originals. Close it without restart to retire the stream, or leave it open.`\n );\n skipped.push(target.stream);\n stream_info.delete(target.stream);\n }\n }\n\n // 2. Partition: skip streams with pending reactions in flight\n const safe = await partition_by_safety(\n stream_info,\n deps.reactive_events_size,\n skipped,\n deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE\n );\n if (!safe.length) return { truncated: windowed_result, skipped };\n\n // 3. Guard: commit a tombstone with expectedVersion per safe stream.\n // Correlation comes from the orchestrator's configured correlator so\n // close commits share the app's id scheme — see ACT-404.\n const { guarded, guard_events } = await guard_with_tombstones(\n safe,\n stream_info,\n deps.correlation,\n deps.tombstone,\n skipped\n );\n if (!guarded.length) return { truncated: windowed_result, skipped };\n\n // 4. Seed: load final state for restart targets through the owning state\n const seed_states = await load_restart_seeds(\n guarded,\n target_map,\n stream_info,\n deps.event_to_state,\n deps.load,\n deps.logger\n );\n\n // 5. Archive: user-provided per-stream callback while guarded\n await run_archive_callbacks(guarded, target_map);\n\n // 6. Truncate + seed: atomic per-store transaction\n const truncated = await truncate_and_warm_cache(\n guarded,\n seed_states,\n guard_events,\n deps.correlation\n );\n\n for (const [stream, entry] of windowed_result) truncated.set(stream, entry);\n return { truncated, skipped };\n}\n\n// ---------------------------------------------------------------------------\n// Windowed branch — prune the prefix behind an existing snapshot\n// ---------------------------------------------------------------------------\n\n/**\n * Run the windowed closes: probe the min consumer watermark per stream\n * (the `max_id` cap that keeps the boundary at/below what the laggiest\n * consumer has read), run archive callbacks against the cutoff, then\n * hand the boundary targets to {@link Store.truncate}.\n *\n * No tombstone guard and no cache touch — the cutoff is always in the\n * past, so a concurrently-written snapshot (`created = now`) can never\n * become the boundary: once the cutoff is fixed the boundary snapshot is\n * fixed, and the prefix below it is immutable. Concurrent appends land\n * at the head, above the boundary. Current state is unchanged, so the\n * cache stays warm. Streams the store skips (no qualifying snapshot)\n * are reported in `skipped`.\n *\n * @internal\n */\nasync function run_windowed_closes(\n windowed: CloseTarget[],\n deps: CloseCycleDeps,\n skipped: string[]\n): Promise<CloseResult[\"truncated\"]> {\n // 1. Safety probe: min consumer watermark per stream. Skipped entirely\n // when the app has no reactions — nothing can lag.\n const min_at =\n deps.reactive_events_size > 0\n ? await probe_min_watermarks(\n windowed.map((t) => t.stream),\n deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE\n )\n : new Map<string, number>();\n\n // 2 + 3. Per stream, under a process-local lock (#1222): probe the\n // boundary, archive against intact history only when the prune would\n // actually delete a prefix, then truncate. Serialization + the\n // \"prune is non-empty\" gate together make the archive fire at most\n // once per pruned range when a manual `app.close` races an autoclose\n // windowed close for the same stream — the second closer, run behind\n // the lock, sees the already-pruned prefix (boundary is now the\n // earliest event) and skips its archive. Each stream is independent,\n // so `truncate` is called per stream inside its own lock rather than\n // once for the batch; a windowed truncate touches only its own stream.\n const with_lock = deps.with_stream_lock ?? ((_stream, work) => work());\n const truncated: CloseResult[\"truncated\"] = new Map();\n for (const t of windowed) {\n const entry = await with_lock(t.stream, async () => {\n const max_id = min_at.get(t.stream);\n // Boundary probe: will a windowed truncate prune anything? The\n // store deletes events with `id < boundary.id`, where `boundary`\n // is the latest `__snapshot__` with `created < before` (and, when\n // capped, `id <= max_id`). No such prefix ⇒ archive is skipped and\n // the stream is reported skipped, exactly as a no-op truncate would.\n if (!(await windowed_prune_pending(t.stream, t.before!, max_id)))\n return undefined;\n // Archive: user callback against the cutoff, run while the prefix\n // is still present. Sequential/fail-fast: a throw propagates to the\n // caller and leaves the stream un-truncated (no data loss).\n if (t.archive) await t.archive();\n // Boundary truncate: atomic per-store transaction; no seed.\n const result = await store().truncate([\n { stream: t.stream, before: t.before!, max_id },\n ]);\n return result.get(t.stream);\n });\n if (entry) truncated.set(t.stream, entry);\n else skipped.push(t.stream);\n }\n return truncated;\n}\n\n/**\n * Read-only probe: would a windowed truncate of `stream` at `before`\n * (optionally capped at `max_id`) delete a prefix? Mirrors the store's\n * boundary rule — the latest `__snapshot__` with `created < before` and,\n * when capped, `id <= max_id` — then reports whether any event sorts\n * strictly below that boundary. False when no snapshot qualifies (a\n * no-op truncate) or when the boundary is already the earliest event\n * (the prefix was pruned by a prior closer). This is the guard that\n * makes the windowed archive fire at most once per pruned range (#1222).\n *\n * @internal\n */\nasync function windowed_prune_pending(\n stream: string,\n before: Date,\n max_id: number | undefined\n): Promise<boolean> {\n let boundary_id: number | undefined;\n let min_id: number | undefined;\n await store().query(\n (event) => {\n if (min_id === undefined || event.id < min_id) min_id = event.id;\n if (\n event.name === SNAP_EVENT &&\n event.created < before &&\n (max_id === undefined || event.id <= max_id) &&\n (boundary_id === undefined || event.id > boundary_id)\n )\n boundary_id = event.id;\n },\n { stream, stream_exact: true, with_snaps: true, after: -1 }\n );\n // No qualifying snapshot → nothing to prune behind. Otherwise a prune\n // is pending only when some event sorts below the boundary.\n return boundary_id !== undefined && min_id! < boundary_id;\n}\n\n/**\n * Min subscription watermark per target stream — the read-only probe\n * backing the windowed close's `max_id` cap. Pagination and source\n * matching mirror {@link partition_by_safety}; instead of flagging\n * pending streams it folds `min(at)` per stream. Streams with no\n * matching subscriptions are absent (no cap).\n *\n * @internal\n */\nasync function probe_min_watermarks(\n streams: string[],\n page_size: number\n): Promise<Map<string, number>> {\n const min_at = new Map<string, number>();\n const source_regex = new Map<string, RegExp>();\n const get_regex = (source: string): RegExp => {\n let re = source_regex.get(source);\n if (!re) {\n re = new RegExp(source);\n source_regex.set(source, re);\n }\n return re;\n };\n\n let after: string | undefined;\n for (;;) {\n let last: string | undefined;\n const { count } = await store().query_streams(\n (position) => {\n last = position.stream;\n const source_re = position.source\n ? get_regex(position.source)\n : undefined;\n for (const stream of streams) {\n if (!source_re || source_re.test(stream)) {\n const prev = min_at.get(stream);\n if (prev === undefined || position.at < prev)\n min_at.set(stream, position.at);\n }\n }\n },\n { after, limit: page_size, source_matches: streams }\n );\n if (count < page_size) break;\n after = last;\n }\n return min_at;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 1 — scan stream heads\n// ---------------------------------------------------------------------------\n\nasync function scan_stream_heads(\n streams: string[]\n): Promise<Map<string, StreamHead>> {\n // query_stats returns the latest non-snap event per stream (heads-only\n // cheap path, indexed). Streams whose latest non-snap event is a tombstone\n // are filtered out in the loop — we don't want to re-tombstone an\n // already-closed stream. Streams with no events (or only snap/tombstone\n // events filtered out) are absent from the result map entirely.\n const stats = await store().query_stats(streams, {\n exclude: [SNAP_EVENT],\n });\n // Domain head, markers excluded. A stream absent here has no domain\n // events left, so a previous close ran to completion and there is\n // nothing to do. A stream present here whose `stats` head is a tombstone\n // was guarded and then interrupted — it must be resumed, not skipped\n // (#1389). `last_event_name` also has to come from this pass: the\n // restart-seed owner lookup needs the domain event, not the marker.\n const domain_heads = await store().query_stats(streams, {\n exclude: [SNAP_EVENT, TOMBSTONE_EVENT],\n });\n // The tombstone's optimistic lock must expect the stream's ACTUAL current\n // version, which is one higher when a `__snapshot__` trails the domain head\n // — `snap()` commits it into the next version slot (event-sourcing.ts). The\n // domain head above still drives `max_id` (the safety probe: a subscription\n // advances its watermark on domain events, never snapshots) and\n // `last_event_name` (the restart-seed owner lookup). Only the guard version\n // needs the true head, so a second heads-only pass reads it with snapshots\n // included. Without this, a terminal commit that crossed a `.snap()`\n // boundary makes the guard expect a stale version and skip the close (#1356).\n const true_heads = await store().query_stats(streams, {});\n const out = new Map<string, StreamHead>();\n for (const [stream, { head }] of domain_heads) {\n const marker_head = stats.get(stream)?.head;\n const interrupted = marker_head?.name === TOMBSTONE_EVENT;\n out.set(stream, {\n max_id: head.id,\n version: true_heads.get(stream)!.head.version,\n last_event_name: head.name as string,\n ...(interrupted ? { resumed_guard: { id: marker_head.id } } : {}),\n });\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2 — partition by safety\n// ---------------------------------------------------------------------------\n\nasync function partition_by_safety(\n stream_info: Map<string, StreamHead>,\n reactive_events_size: number,\n skipped: string[],\n page_size: number\n): Promise<string[]> {\n if (reactive_events_size === 0) return [...stream_info.keys()];\n\n // Read-only probe: query_streams returns subscription positions without\n // leasing or mutating retry state.\n //\n // The stored `source` on a subscription may be a literal stream name or\n // a pattern (e.g. `^(A|B)$`); this probe matches it as a regex against\n // close-target names either way — a literal regex-matches itself, and a\n // pattern matches the streams it claims for. Any metacharacter\n // over-match only widens the pending set — the conservative direction\n // for a safety probe. Compiled patterns are cached because dynamic\n // reactions commonly produce many subscriptions sharing one source, so\n // the callback fires repeatedly with the same `source`.\n const pending_set = new Set<string>();\n const source_regex = new Map<string, RegExp>();\n const get_regex = (source: string): RegExp => {\n let re = source_regex.get(source);\n if (!re) {\n re = new RegExp(source);\n source_regex.set(source, re);\n }\n return re;\n };\n\n // `source_matches` narrows the probe server-side to subscriptions that\n // could consume from a stream we're closing — a best-effort hint, so\n // the per-position source/target re-check below still runs and keeps\n // the result correct even when a store returns a superset.\n const targets = [...stream_info.keys()];\n\n // Keyset-paginate the (narrowed) subscriptions on the `after` cursor —\n // `query_streams` caps each call at `limit` rows, so every page is\n // inspected until a short page signals the last one. A lagging reaction\n // marks its close target pending regardless of how far its subscription\n // sorts past the first page.\n let after: string | undefined;\n for (;;) {\n let last: string | undefined;\n const { count } = await store().query_streams(\n (position) => {\n last = position.stream;\n const source_re = position.source\n ? get_regex(position.source)\n : undefined;\n for (const [stream, info] of stream_info) {\n if (\n (!source_re || source_re.test(stream)) &&\n position.at < info.max_id\n ) {\n pending_set.add(stream);\n }\n }\n },\n { after, limit: page_size, source_matches: targets }\n );\n if (count < page_size) break;\n after = last;\n }\n\n const safe: string[] = [];\n for (const [stream] of stream_info) {\n if (pending_set.has(stream)) skipped.push(stream);\n else safe.push(stream);\n }\n return safe;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 3 — guard with tombstones\n// ---------------------------------------------------------------------------\n\nasync function guard_with_tombstones(\n safe: string[],\n stream_info: Map<string, StreamHead>,\n correlation: string,\n tombstone: EsOps[\"tombstone\"],\n skipped: string[]\n): Promise<{\n guarded: string[];\n guard_events: Map<string, { id: number; stream: string }>;\n}> {\n const guarded: string[] = [];\n const guard_events = new Map<string, { id: number; stream: string }>();\n await Promise.all(\n safe.map(async (stream) => {\n const info = stream_info.get(stream)!;\n if (info.resumed_guard) {\n // Guard already written by the interrupted run — reuse it rather\n // than re-tombstoning (the version guard would reject it anyway).\n guarded.push(stream);\n guard_events.set(stream, { id: info.resumed_guard.id, stream });\n return;\n }\n const committed = await tombstone(stream, info.version, correlation);\n if (committed) {\n guarded.push(stream);\n guard_events.set(stream, { id: committed.id, stream });\n } else {\n // ConcurrencyError → another writer beat the guard\n skipped.push(stream);\n }\n })\n );\n return { guarded, guard_events };\n}\n\n// ---------------------------------------------------------------------------\n// Phase 4 — load restart seeds\n// ---------------------------------------------------------------------------\n\nasync function load_restart_seeds(\n guarded: string[],\n target_map: Map<string, CloseTarget>,\n stream_info: Map<string, StreamHead>,\n event_to_state: ReadonlyMap<string, State<any, any, any>>,\n load: EsOps[\"load\"],\n logger: Logger\n): Promise<Map<string, Schema>> {\n const seed_states = new Map<string, Schema>();\n await Promise.all(\n guarded\n .filter((s) => target_map.get(s)?.restart)\n .map(async (stream) => {\n // stream_info entry is guaranteed (guarded ⊆ stream_info.keys()).\n const last_event_name = stream_info.get(stream)!.last_event_name;\n const owner_state = event_to_state.get(last_event_name);\n if (!owner_state) {\n // No registered state owns the stream's events (deleted state,\n // schema versioning gone wrong, etc.). Tombstone instead of\n // seeding a corrupted snapshot.\n logger.error(\n `Cannot seed restart for \"${stream}\": no registered state owns event \"${last_event_name}\". Stream will be tombstoned instead.`\n );\n return;\n }\n const snap = await load(owner_state, { stream });\n seed_states.set(stream, snap.state as Schema);\n })\n );\n return seed_states;\n}\n\n// ---------------------------------------------------------------------------\n// Phase 5 — archive callbacks\n// ---------------------------------------------------------------------------\n\nasync function run_archive_callbacks(\n guarded: string[],\n target_map: Map<string, CloseTarget>\n): Promise<void> {\n // Sequential — user callbacks may share resources (S3 client, etc.) and\n // a failure should propagate to the caller without leaving partial state.\n for (const stream of guarded) {\n const archive_fn = target_map.get(stream)?.archive;\n if (archive_fn) await archive_fn();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Phase 6 — atomic truncate + cache warm\n// ---------------------------------------------------------------------------\n\nasync function truncate_and_warm_cache(\n guarded: string[],\n seed_states: Map<string, Schema>,\n guard_events: Map<string, { id: number; stream: string }>,\n correlation: string\n): Promise<CloseResult[\"truncated\"]> {\n const trunc_targets = guarded.map((stream) => {\n const snapshot = seed_states.get(stream);\n const guard = guard_events.get(stream)!;\n return {\n stream,\n snapshot,\n meta: {\n correlation,\n causation: {\n event: { id: guard.id, name: TOMBSTONE_EVENT, stream: guard.stream },\n },\n },\n };\n });\n const truncated = await store().truncate(trunc_targets);\n\n // Cache invalidate / warm — use real event IDs from committed events\n await Promise.all(\n guarded.map(async (stream) => {\n const entry = truncated.get(stream);\n const state = seed_states.get(stream);\n if (state && entry) {\n await cache().set(stream, {\n stream,\n state,\n version: entry.committed.version,\n event_id: entry.committed.id,\n patches: 0,\n snaps: 1,\n });\n } else {\n await cache().invalidate(stream);\n }\n })\n );\n\n return truncated;\n}\n","/**\n * @module correlate-cycle\n * @category Internal\n *\n * Correlation — the discovery half of the correlate→drain pair. Owns the\n * lazy init (subscribe static targets, read cold-start watermark), the\n * dynamic-resolver scan that registers new streams as events arrive, and\n * the periodic timer that drives background discovery.\n *\n * The Act orchestrator passes registry + classification (which static\n * targets to subscribe, whether any dynamic resolvers exist) at build\n * time; everything past that lives here.\n *\n * @internal\n */\n\nimport { log, store } from \"../ports.js\";\nimport type {\n Query,\n ReactionPayload,\n Registry,\n SchemaRegister,\n Schemas,\n} from \"../types/index.js\";\nimport type { DrainOps } from \"./drain.js\";\nimport { LruMap } from \"./lru-map.js\";\n\n/**\n * Cold-start back-scan window (ACT-1207). On init the correlate cursor\n * would otherwise jump straight to the store watermark (`max(at)` across\n * every subscribed stream). A dynamic-resolver event committed but not\n * yet correlated before a crash sits *below* that watermark whenever a\n * busier stream has since advanced — so a plain `max(at)` cold start\n * skips it forever, and a one-shot dynamic target is never subscribed.\n *\n * Flooring the cold-start checkpoint at `watermark - BACK_SCAN` re-scans\n * the tail on restart so those in-flight events are re-discovered.\n * Re-scanning already-correlated events is harmless: `_subscribed`\n * dedups and `subscribe` is an idempotent UPSERT. The window bounds the\n * one-time restart cost; steady-state correlation still advances the\n * checkpoint forward normally.\n *\n * @internal\n */\nconst DEFAULT_COLD_START_BACK_SCAN = 10_000;\n\n/**\n * Static resolver target collected at build time. Subscribed once during\n * init; never re-evaluated.\n *\n * @property priority - Scheduling priority for the resolved target stream.\n * Combined with peers via `max()` at build time when multiple reactions\n * target the same stream — see `build-classify.ts`.\n *\n * @internal\n */\nexport type StaticTarget = {\n readonly stream: string;\n readonly source?: string;\n readonly priority?: number;\n readonly lane?: string;\n};\n\n/**\n * Drives correlation for one Act instance. Owns the checkpoint, the\n * subscribed-streams LRU, and the periodic timer.\n *\n * @internal\n */\n/**\n * Constructor dependencies for {@link CorrelateCycle}. A named bag rather\n * than a positional list: the trailing hooks (`on_init`, `on_init_async`)\n * plus `cold_start_back_scan` are all optional and easy to transpose\n * positionally, so callers pass them by name.\n */\nexport type CorrelateCycleDeps<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n> = {\n registry: Registry<TSchemaReg, TEvents, TActions>;\n static_targets: ReadonlyArray<StaticTarget>;\n has_dynamic_resolvers: boolean;\n cd: DrainOps<TEvents>;\n max_subscribed_streams: number;\n run_scoped: <T>(fn: () => Promise<T>) => Promise<T>;\n on_init?: () => void;\n on_init_async?: () => Promise<void>;\n cold_start_back_scan?: number;\n};\n\nexport class CorrelateCycle<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n> {\n private _checkpoint = -1;\n private _initialized = false;\n /** In-flight init, memoized for single-flight and cleared on failure. */\n private _init_promise: Promise<void> | undefined;\n private _timer: ReturnType<typeof setInterval> | undefined = undefined;\n // target → the priority it was last subscribed at. A dynamic target is\n // re-subscribed (so the store's `GREATEST` upsert runs) only when a later\n // scan resolves a *higher* priority for it — the runtime `max()` invariant\n // (#1363). Static targets are recorded at +Infinity so a dynamic resolution\n // never re-opens them (their priority is owned by the build-time subscribe).\n private readonly _subscribed: LruMap<string, number>;\n private readonly _registry: Registry<TSchemaReg, TEvents, TActions>;\n private readonly _static_targets: ReadonlyArray<StaticTarget>;\n private readonly _has_dynamic_resolvers: boolean;\n private readonly _cd: DrainOps<TEvents>;\n private readonly _on_init: (() => void) | undefined;\n /**\n * Async cold-start hook (#1221). Runs once, after the sync `on_init`,\n * inside the same `init()` await. The orchestrator uses it to re-seed the\n * process-local defer timers from the store's persisted `deferred_at` so\n * an idle deferred stream re-arms its drain across a restart. Kept\n * separate from `on_init` because seeding is an async store read; `init`\n * already awaits, so folding it in here preserves the \"runs exactly once\"\n * guarantee without a second gate on the Act side.\n */\n private readonly _on_init_async: (() => Promise<void>) | undefined;\n /**\n * Scope runner (#1191). The periodic `start_polling` timer fires\n * outside any caller frame, so its `correlate()` must be re-wrapped in\n * the Act's `_scoped` bag or `store()`/`cache()` resolve to the\n * singleton for a scoped Act. The orchestrator always threads its\n * `_scoped` (identity for a non-scoped Act), so it's required.\n */\n private readonly _run_scoped: <T>(fn: () => Promise<T>) => Promise<T>;\n /**\n * Tail re-scan window applied to the cold-start checkpoint (ACT-1207).\n * See {@link DEFAULT_COLD_START_BACK_SCAN}. Constructor arg (not a\n * public option) so tests can shrink it; defaults otherwise.\n */\n private readonly _cold_start_back_scan: number;\n\n constructor({\n registry,\n static_targets,\n has_dynamic_resolvers,\n cd,\n max_subscribed_streams,\n run_scoped,\n on_init,\n on_init_async,\n cold_start_back_scan = DEFAULT_COLD_START_BACK_SCAN,\n }: CorrelateCycleDeps<TSchemaReg, TEvents, TActions>) {\n this._subscribed = new LruMap(max_subscribed_streams);\n this._registry = registry;\n this._static_targets = static_targets;\n this._has_dynamic_resolvers = has_dynamic_resolvers;\n this._cd = cd;\n this._on_init = on_init;\n this._run_scoped = run_scoped;\n this._on_init_async = on_init_async;\n this._cold_start_back_scan = cold_start_back_scan;\n }\n\n /** Last correlated event id. */\n get checkpoint(): number {\n return this._checkpoint;\n }\n\n /**\n * Whether any reaction uses a dynamic resolver — i.e. whether `correlate`\n * performs a store scan rather than the static no-op early-return. The\n * settle loop reads this to avoid recording a fictitious circuit-breaker\n * success on a static app whose correlate never touches the store (#1329).\n */\n get has_dynamic_resolvers(): boolean {\n return this._has_dynamic_resolvers;\n }\n\n /**\n * Initialize correlation state on first call.\n * - Reads max(at) from store, then floors the cold-start checkpoint at\n * `watermark - back_scan` when dynamic resolvers exist, so an event\n * committed-but-not-correlated before a crash is re-scanned on\n * restart instead of skipped (ACT-1207)\n * - Subscribes static resolver targets (idempotent upsert)\n * - Populates the subscribed-streams LRU\n * - Fires `on_init` once (Act uses this to flag a cold-start drain)\n */\n async init(): Promise<void> {\n if (this._initialized) return;\n // Single-flight, but retryable: the promise is memoized so concurrent\n // callers (correlate, the settle loop, every lane worker) share one\n // run, and cleared on rejection so a transient store failure doesn't\n // latch. Setting a boolean before the await instead left every static\n // target unsubscribed for the process lifetime after one blip — the\n // reaction pipeline silently dead, with nothing in blocked_streams or\n // the audit to reveal it, because the subscription row never existed.\n if (!this._init_promise) {\n this._init_promise = this._run_init().catch((error) => {\n this._init_promise = undefined;\n throw error;\n });\n }\n await this._init_promise;\n this._initialized = true;\n }\n\n private async _run_init(): Promise<void> {\n const { watermark } = await store().subscribe([...this._static_targets]);\n // Without dynamic resolvers correlate never scans, so the checkpoint\n // is inert — keep the plain `max(at)` cold start. With dynamic\n // resolvers, back the cursor off the watermark by a bounded window so\n // the crash-window tail (an uncorrelated event now below a busier\n // stream's watermark) is re-discovered. Never floor below -1.\n this._checkpoint = this._has_dynamic_resolvers\n ? Math.max(-1, watermark - this._cold_start_back_scan)\n : watermark;\n this._on_init?.();\n for (const { stream } of this._static_targets) {\n // +Infinity: a dynamic resolution's priority can never exceed it, so a\n // static target is never re-subscribed through the dynamic path (#1363).\n this._subscribed.set(stream, Number.POSITIVE_INFINITY);\n }\n // Cold-start defer re-seed (#1221) — after the static targets are\n // subscribed, so a walk of the streams table sees them.\n await this._on_init_async?.();\n }\n\n /**\n * Forget targets whose subscription rows no longer exist, so a later\n * scan can re-subscribe them.\n *\n * A full close deletes the closed stream's subscription row. The\n * in-process dedup would otherwise still believe the target is\n * subscribed and never re-issue `subscribe()`, silently stopping\n * delivery for any reaction whose target is named after the stream —\n * the documented per-aggregate shape `.to(e => ({target: e.stream}))`\n * makes those two namespaces collide by construction (#1398).\n *\n * Static targets are left alone: they are subscribed once at init and\n * recorded at +Infinity so the dynamic path never re-opens them.\n */\n forget_subscribed(streams: Iterable<string>): void {\n const statics = new Set(this._static_targets.map((t) => t.stream));\n for (const stream of streams) {\n if (!statics.has(stream)) this._subscribed.delete(stream);\n }\n }\n\n /**\n * Discover dynamic-resolver targets in the events past the checkpoint\n * and register any new streams via `cd.subscribe`. Static targets are\n * subscribed at init time, so this only walks dynamic resolvers.\n */\n async correlate(\n query: Query = { after: -1, limit: 10 }\n ): Promise<{ subscribed: number; last_id: number }> {\n await this.init();\n\n // No dynamic resolvers — nothing to discover\n if (!this._has_dynamic_resolvers)\n return { subscribed: 0, last_id: this._checkpoint };\n\n // Use checkpoint as floor, allow explicit query.after to override upward\n const after = Math.max(this._checkpoint, query.after || -1);\n const correlated = new Map<\n string,\n {\n source?: string;\n priority: number;\n lane?: string;\n payloads: ReactionPayload<TEvents>[];\n }\n >();\n let last_id = after;\n await store().query<TEvents>(\n (event) => {\n last_id = event.id;\n const register = this._registry.events[event.name];\n // skip events with no registered reactions\n if (register) {\n for (const reaction of register.reactions.values()) {\n // only evaluate dynamic resolvers — statics are subscribed at init\n if (typeof reaction.resolver !== \"function\") continue;\n const resolved = reaction.resolver(event);\n // Let a target through when a scan resolves a strictly higher\n // priority than it was last subscribed at, so the store's\n // `GREATEST` upsert raises it — the documented runtime `max()`\n // invariant, which the plain \"already subscribed?\" dedup silently\n // froze at first discovery (#1363). A never-seen target defaults to\n // -Infinity so its first resolution always passes; static targets\n // sit at +Infinity so a dynamic resolution never re-opens them.\n if (\n resolved &&\n (resolved.priority ?? 0) >\n (this._subscribed.get(resolved.target) ??\n Number.NEGATIVE_INFINITY)\n ) {\n const incoming_priority = resolved.priority ?? 0;\n const entry = correlated.get(resolved.target) || {\n source: resolved.source,\n priority: incoming_priority,\n lane: resolved.lane,\n payloads: [],\n };\n // Multiple reactions targeting the same stream within a\n // single correlate scan — keep the max priority, and carry the\n // winning reaction's lane so the highest-priority reaction sets\n // the lane (matches the subscribe-side `max()` invariant).\n if (incoming_priority > entry.priority) {\n entry.priority = incoming_priority;\n entry.lane = resolved.lane;\n }\n entry.payloads.push({\n ...reaction,\n source: resolved.source,\n event,\n });\n correlated.set(resolved.target, entry);\n }\n }\n }\n },\n { ...query, after }\n );\n\n if (correlated.size) {\n const streams = [...correlated.entries()].map(\n ([stream, { source, priority, lane }]) => ({\n stream,\n source,\n priority,\n lane,\n })\n );\n const { subscribed } = await this._cd.subscribe(streams);\n // Advance checkpoint only after subscribe succeeds\n this._checkpoint = last_id;\n if (subscribed) {\n // Record each target at the priority it was just subscribed at (the\n // within-scan max), so a later lower-or-equal resolution dedups and a\n // strictly-higher one re-opens the guard above (#1363).\n for (const { stream, priority } of streams) {\n this._subscribed.set(stream, priority);\n }\n }\n return { subscribed, last_id };\n }\n // No streams to subscribe — safe to advance\n this._checkpoint = last_id;\n return { subscribed: 0, last_id };\n }\n\n /**\n * Start a periodic correlation worker. Returns false if one is already\n * running. Errors from `correlate()` are routed through `log()` so they\n * land in the configured logger (the timer keeps running on failure).\n */\n start_polling(\n query: Query = {},\n frequency = 10_000,\n callback?: (subscribed: number) => void\n ): boolean {\n if (this._timer) return false;\n\n const limit = query.limit || 100;\n this._timer = setInterval(\n () =>\n this._run_scoped(() =>\n this.correlate({ ...query, after: this._checkpoint, limit })\n )\n .then((result) => {\n if (callback && result.subscribed) callback(result.subscribed);\n })\n .catch((err) => log().error(err)),\n frequency\n );\n return true;\n }\n\n /** Stop the periodic correlation worker. Idempotent. */\n stop_polling(): void {\n if (this._timer) {\n clearInterval(this._timer);\n this._timer = undefined;\n }\n }\n}\n","/**\n * @module correlator\n * @category Internal\n *\n * Correlation-id generator and the default implementation (ACT-404).\n *\n * The default produces a readable, time-monotonic-within-window, lowercase\n * id like `coun-incr-lwxk9p3a` — short enough to scan in logs, structured\n * enough to identify the originating state/action, and well-distributed\n * enough that competing-consumer workers don't collide.\n *\n * Apps override via {@link ActOptions.correlator} to plug in any scheme\n * (tenant-prefixed, trace-id-propagated, DB-sequence-backed, etc.).\n *\n * @internal\n */\n\nimport { randomInt } from \"node:crypto\";\nimport type { Actor, Correlator } from \"../types/index.js\";\n\nconst BASE = 36;\nconst SEG_WIDTH = 4;\nconst SEG_SPACE = BASE ** SEG_WIDTH;\n\nfunction seg(n: number): string {\n return n.toString(BASE).padStart(SEG_WIDTH, \"0\");\n}\n\n/**\n * Default {@link Correlator}. Produces ids of the form\n * `{state[:4]}-{action[:4]}-{4 ms}{4 random}` — 18 characters, lowercase\n * base36.\n *\n * - Prefix carries human-meaningful context (state + action) so operators\n * can identify a workflow at a glance in logs and query results.\n * - The 4-character `Date.now() % 36^4` segment wraps every ~28 minutes,\n * long enough that adjacent inserts in a typical workflow share B-tree\n * pages — index locality, not global sortability, is the goal.\n * - The 4-character random tail gives 1.68M values per ms; collision risk\n * across K=100 concurrent workers is roughly K² / 3.4M per ms.\n *\n * Names shorter than 4 chars are used as-is (no padding) so a state named\n * `Tx` produces `tx-...` rather than `tx00-...`.\n */\nexport const default_correlator: Correlator = ({ state, action }) => {\n const s = state.slice(0, SEG_WIDTH).toLowerCase();\n const a = action.slice(0, SEG_WIDTH).toLowerCase();\n const ts = seg(Date.now() % SEG_SPACE);\n const rnd = seg(randomInt(SEG_SPACE));\n return `${s}-${a}-${ts}${rnd}`;\n};\n\n/**\n * Resolves the correlation id for the close-the-books transaction.\n * Close runs outside any user action, so we synthesize a context with\n * sentinel state/action names — visible in the id when overrides aren't\n * configured.\n *\n * @internal\n */\nexport function close_correlation(\n correlator: Correlator,\n actor: Actor\n): string {\n return correlator({\n state: \"$close\",\n action: \"close\",\n stream: \"$close\",\n actor,\n });\n}\n","/**\n * @module drain-cycle\n * @category Internal\n *\n * Two layers of the drain pipeline:\n *\n * - {@link run_drain_cycle} — pure function for one round-trip of\n * claim → fetch → group → dispatch → ack/block. No orchestrator state.\n * Reusable for property tests and standalone benchmarks.\n *\n * - {@link DrainController} — stateful driver that owns the armed flag,\n * the concurrency lock, and the adaptive lag/lead ratio. Wraps\n * `run_drain_cycle` with the lifecycle decisions Act used to make inline.\n *\n * @internal\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { log } from \"../ports.js\";\nimport type {\n BatchHandler,\n BlockedLease,\n CloseTarget,\n Drain,\n DrainOptions,\n Fetch,\n Lease,\n Logger,\n ReactionPayload,\n Registry,\n SchemaRegister,\n Schemas,\n} from \"../types/index.js\";\nimport type { CircuitBreaker } from \"./circuit-breaker.js\";\nimport { DeferTimer } from \"./defer-timer.js\";\nimport type { DrainOps } from \"./drain.js\";\nimport { compute_lag_lead_ratio } from \"./drain-ratio.js\";\nimport { trace_cycle } from \"./tracing.js\";\n\n/**\n * Outcome of processing a single leased stream — produced by Act's `handle`\n * / `handle_batch` dispatchers, consumed by `run_drain_cycle` to drive ack/block.\n *\n * @internal\n */\nexport type HandleResult = Readonly<{\n lease: Lease;\n handled: number;\n /**\n * Event id at which the ack would land — the last *successful* event\n * id, or `lease.at` when the batch had no work (empty payloads). Named\n * `acked_at` to pair symmetrically with {@link failed_at} and to keep\n * it visually distinct from `Lease.at` (the pre-cycle watermark — same\n * field name across types but a different semantic).\n */\n acked_at: number;\n error?: string;\n block?: boolean;\n /**\n * Wall-clock timestamp (ms since epoch) at which the next attempt on\n * this stream may run. Populated by `_finalize` only on retry paths\n * where the reaction defined `options.backoff`. Undefined means \"no\n * backoff configured\" — drain re-attempts as soon as the lease expires.\n */\n next_attempt_at?: number;\n /**\n * Wall-clock timestamp (ms since epoch) at which this stream should be\n * re-visited. Set by a handler that *defers* instead of acking or\n * failing: the triggering events stay pending (watermark not advanced),\n * `retry` is not bumped (a defer is not a failure), and the drain holds\n * the stream until `defer` elapses, then redelivers so the handler can\n * re-evaluate. This is the timing primitive autoclose rides (#1090);\n * unlike {@link next_attempt_at} (a retry-only backoff), a defer carries\n * no error and never blocks. When present, the result is excluded from\n * ack and block — it neither advances nor terminates the watermark.\n */\n defer?: number;\n /**\n * Close request (#1090). Set when a handler throws `CloseSignal` to retire\n * its stream: the triggering event is acked (so the closing reaction isn't\n * seen as an in-flight consumer by the close-cycle safety guard) and the\n * drain hands this {@link CloseTarget} to the orchestrator's `on_close`,\n * which runs `run_close_cycle`. Carries the optional archiver from the\n * signal. Distinct from {@link defer} (hold for later) — a close advances\n * and retires.\n */\n close?: CloseTarget;\n /**\n * Event id that threw, when a handler error occurred. Distinct from\n * {@link acked_at}: `failed_at = acked_at + 1` in dense streams, but\n * adapters with sparse ids give the trace the exact position. Always\n * set on the per-event error path; absent in batch mode (where no\n * single event id can be attributed to the failure).\n */\n failed_at?: number;\n}>;\n\n/**\n * Per-event reaction dispatcher signature (matches `Act.handle`).\n * @internal\n */\nexport type Handle<TEvents extends Schemas> = (\n lease: Lease,\n payloads: ReactionPayload<TEvents>[]\n) => Promise<HandleResult>;\n\n/**\n * Bulk reaction dispatcher signature (matches `Act.handle_batch`).\n * @internal\n */\nexport type HandleBatch<TEvents extends Schemas> = (\n lease: Lease,\n payloads: ReactionPayload<TEvents>[],\n batchHandler: BatchHandler<TEvents>\n) => Promise<HandleResult>;\n\n/**\n * One drain cycle's results. Returned by {@link run_drain_cycle}; consumed by\n * `Act.drain()` to update lifecycle state, the lag/lead ratio, and emit the\n * `acked` / `blocked` lifecycle events.\n *\n * @internal\n */\nexport type DrainCycle<TEvents extends Schemas> = {\n readonly leased: Lease[];\n readonly fetched: Fetch<TEvents>;\n readonly handled: HandleResult[];\n readonly acked: Lease[];\n readonly blocked: BlockedLease[];\n /** Streams a handler asked to close this cycle (#1090) — handed to `on_close`. */\n readonly closeable: CloseTarget[];\n};\n\n/**\n * Terminal result for a stream whose retry budget was spent without a single\n * attempt ever reaching the block decision — or `undefined` when the stream\n * still has budget.\n *\n * The budget is consulted on the *error* path (`finalize` returns early when\n * a handler didn't throw), so it only terminates handlers that fail loudly. A\n * handler that fails by overrunning its lease never throws: it completes,\n * submits an ack the store drops (`WHERE leased_by = by`), and the next claim\n * bumps `retry` again. `retry` climbs without bound, the watermark never\n * advances, and the side effect re-runs forever — the one outcome\n * `blockOnError` exists to prevent (#1418).\n *\n * The threshold is strictly greater than `maxRetries`, not `>=`, and that is\n * load-bearing. A stream legitimately reaches `retry === maxRetries` on its\n * final attempt, which `finalize` is entitled to run and block only if it\n * fails again. Blocking here at `>=` would take that attempt away and change\n * every error-driven path. At `>` the only way to arrive is with the budget\n * already spent and no attempt having produced an error — a lease lost every\n * single round, which is the stuck stream and nothing else.\n *\n * Gated on `blockOnError` for the same reason `finalize` is: an operator who\n * opted out of blocking chose \"retry forever,\" and that choice holds here too.\n *\n * @internal\n */\nfunction budget_exhausted<TEvents extends Schemas>(\n lease: Lease,\n options: ReactionPayload<TEvents>[\"options\"] | undefined\n): HandleResult | undefined {\n if (!options?.blockOnError || lease.retry <= options.maxRetries)\n return undefined;\n const error = `Blocking ${lease.stream} after ${lease.retry} claims with no acknowledged progress — the lease was lost on every attempt, so the retry budget (${options.maxRetries}) was spent without the handler ever reporting an error. Raise leaseMillis for this handler, then unblock the stream.`;\n log().error(error);\n return { lease, handled: 0, acked_at: lease.at, error, block: true };\n}\n\n/**\n * Run one drain cycle: claim streams, fetch their events, dispatch\n * matching reactions, ack the successes, block the retries-exhausted.\n *\n * Returns `undefined` when nothing was claimed — caller can short-circuit\n * the rest of the drain pass.\n *\n * **Deferred streams** (backoff windows and explicit defers) are excluded\n * upstream by `claim`: their persisted `deferred_at` gates re-dispatch, so\n * they never reach this cycle until the schedule elapses.\n *\n * @internal\n */\nexport async function run_drain_cycle<\n TEvents extends Schemas,\n TActions extends Schemas,\n TSchemaReg extends SchemaRegister<TActions>,\n>(\n ops: DrainOps<TEvents>,\n registry: Registry<TSchemaReg, TEvents, TActions>,\n batch_handlers: Map<string, BatchHandler<TEvents>>,\n handle: Handle<TEvents>,\n handle_batch: HandleBatch<TEvents>,\n lagging: number,\n leading: number,\n eventLimit: number,\n leaseMillis: number,\n /**\n * Emitted as soon as `block` confirms, BEFORE the `ack` that follows.\n * A block is terminal: every adapter gates `block` on `blocked = false`\n * and excludes a blocked stream from `claim`, so it never runs again for\n * that stream. If the emit waited until the end of the cycle, an `ack`\n * failure in between would lose the `blocked` event permanently (#1390).\n */\n on_blocked: (blocked: BlockedLease[]) => void,\n lane?: string\n): Promise<DrainCycle<TEvents> | undefined> {\n // Atomically discover and lease streams (competing consumer pattern)\n const leased = await ops.claim(\n lagging,\n leading,\n randomUUID(),\n leaseMillis,\n lane\n );\n if (!leased.length) return undefined;\n\n // Fetch events for each leased stream. Streams in a backoff window are\n // already excluded here: the store persists `deferred_at` on a due-marked\n // ack and `claim` skips streams whose schedule hasn't elapsed (#1262), so\n // a paced retry never reaches dispatch and no local skip-gate is needed.\n const fetched = await ops.fetch(leased, eventLimit);\n\n // Build a single index keyed by stream — collapses two passes\n // (payloads_map build + per-lease fetched.find) into one Map lookup.\n type FetchEntry = (typeof fetched)[number];\n const fetch_map = new Map<\n string,\n { fetch: FetchEntry; payloads: ReactionPayload<TEvents>[] }\n >();\n\n // compute fetch window max event id\n const fetch_window_at = fetched.reduce(\n (max, { at, events }) => Math.max(max, events.at(-1)?.id || at),\n 0\n );\n\n for (const f of fetched) {\n const { stream, events } = f;\n const payloads = events.flatMap((event) => {\n const register = registry.events[event.name];\n if (!register) return [];\n return [...register.reactions.values()]\n .filter((reaction) => {\n const resolved =\n typeof reaction.resolver === \"function\"\n ? reaction.resolver(event)\n : reaction.resolver;\n return resolved && resolved.target === stream;\n })\n .map((reaction) => ({ ...reaction, event }));\n });\n fetch_map.set(stream, { fetch: f, payloads });\n }\n\n const handled = await Promise.all(\n leased.map((lease) => {\n // fetch() returns one entry per leased stream — fetch_map.get is\n // always defined here (asserted with `!`).\n const entry = fetch_map.get(lease.stream)!;\n // fast-forward watermark using fetched events or window max\n const at = entry.fetch.events.at(-1)?.id || fetch_window_at;\n const { payloads } = entry;\n const exhausted = budget_exhausted(lease, payloads[0]?.options);\n if (exhausted) return Promise.resolve(exhausted);\n const batchHandler = batch_handlers.get(lease.stream);\n if (batchHandler && payloads.length > 0) {\n return handle_batch({ ...lease, at }, payloads, batchHandler);\n }\n return handle({ ...lease, at }, payloads);\n })\n );\n\n // Finalize the cycle in one atomic store call. Every entry advances the\n // watermark to the last event fully handled this cycle, and a deferred or\n // backing-off entry rides the same batch marked with `due` so the store\n // ALSO persists the schedule — advance and defer are independent legs of\n // one ack (#1278). A failed finalize lands nothing — the catch in the\n // controller covers every outcome uniformly. Partial-success-then-block\n // still lands in both `acked` and `blocked` for the same stream — by design.\n //\n // The advance target is `acked_at` (the last fully-handled event) when the\n // batch made progress, and the pre-fetch watermark `floor` (`leased[i].at`,\n // a no-op advance) when it did not — because on a no-progress failure\n // `acked_at` is initialized to the fetch ceiling and would skip the failed\n // event. `leased[i]` pairs with `handled[i]` (Promise.all preserves order),\n // so `floor` is the untouched claim watermark.\n //\n // Deferring past the succeeded prefix (rather than holding the whole batch)\n // is the point: the handled events never re-run on redelivery. A backoff\n // retry carries the climbing `retry` so the budget keeps accruing toward\n // `blockOnError` and the durable cross-worker window (#1262) survives; an\n // explicit defer passes `retry: -1` because a defer is not a failure.\n //\n // `block` runs BEFORE `ack` (#1296). Both stores gate `block` on the lease\n // still being held (`WHERE leased_by = by AND blocked = false`), but `ack`\n // releases the lease (`leased_by = NULL`). A partial-progress-then-block\n // entry (`handled > 0` AND `block: true` — e.g. a `NonRetryableError` on the\n // second event of a batch) is passed to BOTH: `block` marks it poison\n // without touching the watermark, then `ack` advances past the handled\n // prefix and releases the lease. Acking first would release the lease out\n // from under `block`, silently dropping it — the stream would re-run its\n // permanently-failed tail next cycle. Neither store clears the watermark on\n // `block`, so the ordering leaves both legs intact.\n const blocked = await ops.block(\n handled\n .filter(({ block }) => block)\n .map(({ lease, error }) => ({ ...lease, error: error! }))\n );\n\n if (blocked.length) on_blocked(blocked);\n\n const submitted = handled.flatMap((h, i) => {\n const advance = h.handled > 0 ? h.acked_at : leased[i].at;\n return h.defer !== undefined\n ? { ...h.lease, at: advance, due: h.defer, retry: -1 }\n : h.next_attempt_at !== undefined\n ? { ...h.lease, at: advance, due: h.next_attempt_at }\n : h.handled > 0 || !h.error\n ? { ...h.lease, at: h.acked_at }\n : [];\n });\n const acked = await ops.ack(submitted);\n\n // Every adapter gates `ack` on the lease still being held\n // (`WHERE leased_by = by`) — correctly, since that is what stops an\n // evicted holder from regressing a watermark a competitor advanced. But\n // the loss came back as a SHORT RETURN with no error, and nothing compared\n // the two, so a worker whose lease was stolen mid-handler discarded a full\n // round of work with no signal anywhere (#1418).\n //\n // Deferred entries are excluded from ack's return by contract, so they are\n // not \"missing\" — only non-due submissions are counted here.\n const expected = submitted.filter((l) => l.due === undefined).length;\n if (acked.length < expected)\n log().error(\n new Error(\n `drain: ${expected - acked.length} of ${expected} acks were dropped — the lease was taken by another worker mid-handler. That work will be redelivered (at-least-once), but persistent drops mean leaseMillis is too short for this handler.`\n )\n );\n\n // Collect close requests (#1090). A close result was already acked above\n // (its event made progress, `defer === undefined`), which advances the\n // requesting reaction past the terminal event so the close-cycle safety\n // guard doesn't count it as an in-flight consumer. The orchestrator's\n // `on_close` runs the actual `run_close_cycle`.\n const closeable = handled\n .filter((h) => h.close !== undefined)\n .map((h) => h.close!);\n\n return { leased, fetched, handled, acked, blocked, closeable };\n}\n\n/**\n * Empty drain result returned when the controller short-circuits (not\n * armed, locked out by a concurrent caller, claim returned nothing,\n * cycle threw).\n *\n * @internal\n */\nconst EMPTY_DRAIN: Drain<Schemas> = {\n fetched: [],\n leased: [],\n acked: [],\n blocked: [],\n};\n\n/**\n * Dependencies the {@link DrainController} needs from the orchestrator.\n * The lifecycle event sinks (`on_acked` / `on_blocked`) are callbacks so\n * this module doesn't reach back into Act's emitter.\n *\n * @internal\n */\nexport type DrainControllerDeps<\n TEvents extends Schemas,\n TActions extends Schemas,\n TSchemaReg extends SchemaRegister<TActions>,\n> = {\n readonly logger: Logger;\n readonly ops: DrainOps<TEvents>;\n readonly registry: Registry<TSchemaReg, TEvents, TActions>;\n readonly batch_handlers: Map<string, BatchHandler<TEvents>>;\n readonly handle: Handle<TEvents>;\n readonly handle_batch: HandleBatch<TEvents>;\n readonly on_acked: (acked: Lease[]) => void;\n readonly on_blocked: (blocked: BlockedLease[]) => void;\n /**\n * Close requested by a reaction (#1090). The controller calls this with the\n * cycle's {@link CloseTarget}s after acks/blocks land; the orchestrator wires\n * it to its `run_close_cycle` machinery (same path as `app.close`). Awaited so\n * a slow close doesn't overlap the next cycle's claim on the controller.\n */\n readonly on_close: (targets: CloseTarget[]) => Promise<void>;\n /**\n * Shared, orchestrator-owned circuit breaker (ACT-984). Trips after\n * repeated store failures so the drain loop stops hammering a down\n * backend; closed/half-open let attempts through. It also surfaces each\n * failure (via its own `on_error`, wired by the orchestrator to the\n * `error` lifecycle event), so callers just `failed(now, error)`.\n */\n readonly breaker: CircuitBreaker;\n /**\n * Scope runner (#1191). The per-lane worker (`start`) ticks outside\n * any caller frame, so its `drain()` must be re-wrapped in the Act's\n * `_scoped` bag or `store()`/`cache()` resolve to the singleton for a\n * scoped Act. The orchestrator always threads its `_scoped` (identity\n * for a non-scoped Act), so it's required.\n */\n readonly run_scoped: <T>(fn: () => Promise<T>) => Promise<T>;\n /** Lane this controller drains. Undefined = spans all lanes (legacy single-controller). */\n readonly lane?: string;\n /** Per-lane defaults applied when caller doesn't override via DrainOptions. */\n readonly defaults?: {\n readonly streamLimit?: number;\n readonly eventLimit?: number;\n readonly leaseMillis?: number;\n };\n};\n\n/**\n * Stateful driver around {@link run_drain_cycle}. Owns:\n *\n * - `_armed` — has any commit / reset / cold-start signaled work to do?\n * - `_locked` — concurrent-call guard (overlapping `drain()` calls return\n * an empty result instead of running twice)\n * - `_ratio` — adaptive lag-to-lead frontier split, updated per cycle\n *\n * The orchestrator owns commits, lifecycle emission, and `arm()` triggers\n * — the controller owns everything between those edges.\n *\n * @internal\n */\nexport class DrainController<\n TEvents extends Schemas,\n TActions extends Schemas,\n TSchemaReg extends SchemaRegister<TActions>,\n> {\n private _armed = false;\n private _locked = false;\n private _ratio = 0.5;\n /**\n * Per-stream re-visit schedule (#1090): `stream → next visit` (ms since\n * epoch). Holds both retry backoff (`HandleResult.next_attempt_at`) and the\n * `defer` outcome; cleared on successful ack or terminal block. Lives in\n * process memory — per-worker pacing by design (see {@link BackoffOptions}\n * for the multi-worker trade-off). Its wake re-arms drain at the earliest\n * pending visit.\n */\n private readonly _defer = new DeferTimer(() => {\n this._armed = true;\n });\n /** Worker timer (ACT-1103). Set when `start()` is active, undefined otherwise. */\n private _worker: ReturnType<typeof setTimeout> | undefined;\n private _stopped = false;\n\n private readonly _deps: DrainControllerDeps<TEvents, TActions, TSchemaReg>;\n\n constructor(deps: DrainControllerDeps<TEvents, TActions, TSchemaReg>) {\n this._deps = deps;\n }\n\n /**\n * Signal that a commit (or reset / cold-start) may have produced work.\n * Subsequent `drain()` calls will run the pipeline; once the pipeline\n * settles to no-progress, the controller disarms itself.\n */\n arm(): void {\n this._armed = true;\n }\n\n /**\n * Re-seed a persisted defer schedule into the process-local timer at cold\n * start (#1221). The `_defer` map lives in worker memory and is empty\n * after a restart; a stream deferred to a future due-time (e.g. an idle\n * autoclose aggregate) is durable in the store's `deferred_at` but has\n * nothing in memory to re-arm the drain at the due-time. The orchestrator\n * reads the persisted `deferred_at` for this controller's lane and calls\n * this to park the stream + (re)schedule the shared wake — so the drain\n * re-arms at the due-time with no intervening commit. `schedule()`\n * collapses many seeds into one timer, so callers may seed in a loop and\n * let the earliest due-time win.\n */\n seed_defer(stream: string, at: number): void {\n this._defer.set(stream, at);\n this._defer.schedule();\n }\n\n /** Read-only flag — true while a commit / reset is unprocessed. */\n get armed(): boolean {\n return this._armed;\n }\n\n /** Lane this controller drains (undefined = legacy single-lane span). */\n get lane(): string | undefined {\n return this._deps.lane;\n }\n\n /**\n * Start a per-lane worker that drains at the lane's `cycleMs`\n * cadence (ACT-1103). When armed, the worker calls `drain()` on every\n * tick and re-schedules; when not armed, it still re-schedules at\n * `cycleMs` so a future `arm()` is picked up on the next tick.\n *\n * The setTimeout chain uses `unref()` so it doesn't keep the process\n * alive on its own.\n */\n start(cycleMs: number): void {\n if (this._worker || this._stopped) return;\n // `drain()` swallows its own errors and returns EMPTY_DRAIN, so the\n // tick is exception-free by contract. The post-drain `_stopped`\n // check prevents re-scheduling after `stop()` was called mid-tick;\n // an already-queued timer that fires before `clearTimeout()` lands\n // will run at most one extra drain (drain is idempotent against\n // a non-armed controller and self-disarms when settled).\n const run = this._deps.run_scoped;\n const tick = async () => {\n if (this._armed) await run(() => this.drain());\n if (this._stopped) return;\n this._worker = setTimeout(tick, cycleMs);\n this._worker.unref();\n };\n this._worker = setTimeout(tick, cycleMs);\n this._worker.unref();\n }\n\n /** Stop the per-lane worker. Idempotent. */\n stop(): void {\n this._stopped = true;\n if (this._worker) {\n clearTimeout(this._worker);\n this._worker = undefined;\n }\n // Drop any pending re-visit wake — the parked set is process-local and\n // rebuilt from the log on the next start (#1090).\n this._defer.stop();\n }\n\n /** Run one drain pass. Short-circuits when not armed or already running. */\n async drain(options: DrainOptions = {}): Promise<Drain<TEvents>> {\n if (!this._armed) return EMPTY_DRAIN as Drain<TEvents>;\n if (this._locked) return EMPTY_DRAIN as Drain<TEvents>;\n // Circuit open: the store is failing, skip the claim entirely so we\n // don't hammer a down backend. `_armed` stays set, so the next tick\n // after the cooldown (half-open) retries.\n if (this._deps.breaker.state(Date.now()) === \"open\")\n return EMPTY_DRAIN as Drain<TEvents>;\n\n const d = this._deps.defaults ?? {};\n // Per-lane config wins over caller options (ACT-1103). The whole\n // point of `withLane({leaseMillis: 30_000})` is to give the slow\n // lane its own budget — a caller-level drain({leaseMillis}) would\n // erase it. Caller options apply only when the lane didn't pin a\n // value.\n const streamLimit = d.streamLimit ?? options.streamLimit ?? 10;\n const eventLimit = d.eventLimit ?? options.eventLimit ?? 10;\n const leaseMillis = d.leaseMillis ?? options.leaseMillis ?? 10_000;\n\n try {\n this._locked = true;\n const lagging = Math.ceil(streamLimit * this._ratio);\n const leading = streamLimit - lagging;\n\n const cycle = await run_drain_cycle(\n this._deps.ops,\n this._deps.registry,\n this._deps.batch_handlers,\n this._deps.handle,\n this._deps.handle_batch,\n lagging,\n leading,\n eventLimit,\n leaseMillis,\n (b) => this._deps.on_blocked(b),\n this._deps.lane\n );\n\n // The store responded (claim/fetch/ack+defer/block all succeeded) —\n // reset the breaker even when there was no work to do. A failed\n // finalize never reaches here: `Store.ack` applies watermarks and\n // defer schedules atomically, so it either all landed or the\n // whole cycle threw into the catch below and nothing did.\n if (!cycle) {\n // claim() returned no leases — fully caught up\n this._deps.breaker.passed();\n this._armed = false;\n return EMPTY_DRAIN as Drain<TEvents>;\n }\n\n const { leased, fetched, handled, acked, blocked, closeable } = cycle;\n\n // Cycle-level trace (ACT-1103) — one log line per drain pass:\n // claim + fetch + outcomes folded together so the operator sees\n // a single atomic narrative for each cycle. No-op when the\n // logger isn't at trace level.\n trace_cycle(this._deps.logger, leased, fetched, handled, acked, blocked);\n\n // Adapt next cycle's frontier split to where the pressure is.\n this._ratio = compute_lag_lead_ratio(handled, lagging, leading);\n\n // Refresh per-stream re-visit state from this cycle's outcomes.\n // Successful acks and terminal blocks both clear the window;\n // retry-not-block results carry a `next_attempt_at` set by `_finalize`,\n // and deferred results carry a `defer` due-time (#1090). Both park the\n // stream in `_defer` so the shared wake timer re-arms drain at the\n // earliest pending visit. `handle` already reconciles a stream's\n // reactions into a single result per cycle, so the value written here\n // is authoritative for the stream — a plain overwrite, not a merge.\n for (const lease of acked) this._defer.delete(lease.stream);\n for (const lease of blocked) this._defer.delete(lease.stream);\n for (const h of handled) {\n const next = h.defer ?? (h.block ? undefined : h.next_attempt_at);\n if (next !== undefined) this._defer.set(h.lease.stream, next);\n }\n if (this._defer.size > 0) this._defer.schedule();\n\n // Lifecycle sinks are contained individually, mirroring the\n // `notified` handler in `act.ts`. The durable work is already\n // committed by this point, so a throwing listener must not unwind\n // into the store-error `catch` below: that would report a store\n // failure that never happened, return an empty Drain, and — because\n // `block` is guarded on `blocked = false` and a blocked stream is\n // excluded from `claim` — permanently lose the `blocked` event and\n // any reaction-requested close. Listener containment itself lives in\n // `Act.emit`, which guards each listener individually (#1437) — the\n // sinks here are plain calls.\n if (acked.length) this._deps.on_acked(acked);\n // Run reaction-requested closes after acks land (#1090) — the close\n // targets were acked above, so the close-cycle guard sees the requesting\n // reaction as caught up. Awaited so a slow close doesn't overlap the\n // next claim.\n // NOT contained: `on_close` runs the close machinery (load,\n // tombstone, archive, truncate), not an emit. A StoreError raised in\n // there is a real store failure and must reach the breaker via the\n // catch below, or an outage silently bricks streams while the\n // breaker records a success (#1388). The `closed` EMIT is contained\n // on the Act side, which is the only listener risk on this path.\n if (closeable.length) await this._deps.on_close(closeable);\n\n // Recorded after `on_close` so a cycle whose close failed is never\n // counted as a store success (#1388).\n this._deps.breaker.passed();\n\n // Disarm only when fully caught up. Errors keep the flag set so\n // retries flow through the next drain.\n const has_errors = handled.some(({ error }) => error);\n if (!acked.length && !blocked.length && !has_errors) this._armed = false;\n\n return { fetched, leased, acked, blocked };\n } catch (error) {\n // A store op threw (StoreError, or any failure mid-cycle). Record it\n // on the breaker, which logs it and surfaces the `error` lifecycle\n // event. `_armed` stays set so the breaker's retry re-attempts after\n // the cooldown. EMPTY_DRAIN keeps the worker tick exception-free.\n this._deps.breaker.failed(Date.now(), error);\n return EMPTY_DRAIN as Drain<TEvents>;\n } finally {\n this._locked = false;\n }\n }\n}\n","/**\n * @module defer-timer\n * @category Internal\n *\n * The shared \"next visit time\" primitive (#1090). A `DeferTimer` holds a\n * `stream → due-time` map and a single collapsed wake timer: it parks\n * streams that should be re-visited later and fires one `on_wake` callback\n * at the earliest pending due-time, garbage-collecting the entries that have\n * come due.\n *\n * Two consumers ride it:\n *\n * - the {@link \"drain-cycle\".DrainController} — for per-reaction backoff (a\n * retry's `next_attempt_at`) and, once handlers can express it, the\n * `defer` outcome that holds a stream pending without advancing the\n * watermark or bumping `retry`.\n * - the autoclose controller — to schedule its next eligibility check at the\n * precise time an `after`-style cooldown elapses, instead of a blind\n * fixed-interval sweep.\n *\n * Lives in process memory, per worker — the same per-worker pacing trade-off\n * documented for backoff. Durability comes from the data the due-time is\n * *derived* from (an un-advanced watermark, an event's `created` timestamp),\n * not from the map. A restart empties the map, so the cold-start rebuild is\n * explicit: `CorrelateCycle.init` seeds each still-future `deferred_at` back\n * onto the owning lane's timer via {@link \"drain-cycle\".DrainController.seed_defer}\n * (#1221), so an idle deferred stream re-arms at its due-time with no\n * intervening commit.\n *\n * @internal\n */\n\n/**\n * A min-heap-free scheduler over a small `stream → due-time` map. The maps\n * are bounded by the worker's claim/stream limits, so a linear scan for the\n * earliest entry is cheaper than maintaining a heap.\n *\n * @internal\n */\n\n/**\n * Node's `setTimeout` delay is a 32-bit signed int (~24.8 days). A larger\n * delay overflows and fires immediately, so we cap at this and re-arm.\n *\n * @internal\n */\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\n\nexport class DeferTimer {\n private readonly _due = new Map<string, number>();\n private _timer: ReturnType<typeof setTimeout> | undefined;\n private readonly _on_wake: () => void;\n\n /**\n * @param on_wake - invoked once each time the earliest due-time elapses,\n * after the come-due entries have been removed. Consumers use it to\n * re-arm their loop (the drain sets its `armed` flag; autoclose runs a\n * tick).\n */\n constructor(on_wake: () => void) {\n this._on_wake = on_wake;\n }\n\n /** Number of currently parked streams. */\n get size(): number {\n return this._due.size;\n }\n\n /**\n * True while `stream` is parked with a due-time still in the future.\n * Consumers skip work for deferred streams until their window elapses.\n */\n is_deferred = (stream: string): boolean => {\n const next = this._due.get(stream);\n return next !== undefined && next > Date.now();\n };\n\n /**\n * Park `stream` for a re-visit at `at` (ms since epoch). A plain\n * overwrite: the caller computes the authoritative next-visit for the\n * stream (the drain's `handle` already reconciles a stream's reactions\n * into one result per cycle), so there is no stale value to merge against.\n */\n set(stream: string, at: number): void {\n this._due.set(stream, at);\n }\n\n /** Drop `stream` from the parked set (e.g. on a successful ack or block). */\n delete(stream: string): void {\n this._due.delete(stream);\n }\n\n /**\n * (Re)schedule the wake timer at the earliest pending due-time. Idempotent\n * — collapses many parked streams into a single timer. A no-op clears any\n * pending timer when the map is empty.\n *\n * The timer is `unref()`-ed so pending re-visits never keep the process\n * alive on their own.\n */\n schedule(): void {\n if (this._timer) clearTimeout(this._timer);\n if (this._due.size === 0) {\n this._timer = undefined;\n return;\n }\n let earliest = Number.POSITIVE_INFINITY;\n for (const t of this._due.values()) if (t < earliest) earliest = t;\n // Clamp to setTimeout's 32-bit ceiling (~24.8 days). A longer due-time\n // (e.g. a 90-day autoclose cooldown) would otherwise overflow and Node\n // fires it immediately, busy-looping. Instead we wake at the ceiling and\n // re-arm: the GC below keeps the still-future entry, `on_wake` re-schedules\n // for the remaining span, and (for persisted defers) `claim` skips the\n // stream until its real due-time anyway.\n const delay = Math.min(\n Math.max(0, earliest - Date.now()),\n MAX_TIMER_DELAY_MS\n );\n this._timer = setTimeout(() => {\n this._timer = undefined;\n // Garbage-collect the entries that have come due so the consumer's\n // next pass sees them as active again.\n const now = Date.now();\n let came_due = false;\n for (const [stream, at] of this._due)\n if (at <= now) {\n this._due.delete(stream);\n came_due = true;\n }\n this._on_wake();\n // Premature ceiling clamp: nothing came due, yet entries remain — the\n // earliest due-time was past the 32-bit `setTimeout` ceiling, so this\n // wake fired early. The consumer's `on_wake` won't re-arm (the drain's\n // just sets its armed flag, and its next pass early-returns while the\n // stream is still store-excluded), so the primitive must self-re-arm or\n // a >ceiling defer/cooldown loses its precise wake (#1288). A normal wake\n // (something came due) leaves re-arming to the consumer, preserving the\n // fire-once-per-schedule model.\n if (!came_due && this._due.size > 0) this.schedule();\n }, delay);\n this._timer.unref();\n }\n\n /** Cancel any pending wake timer. Idempotent. Leaves the parked set intact. */\n stop(): void {\n if (this._timer) {\n clearTimeout(this._timer);\n this._timer = undefined;\n }\n }\n}\n","/**\n * @module drain-ratio\n * @category Internal\n *\n * Adaptive lag-to-lead ratio for the dual-frontier drain strategy.\n *\n * The orchestrator splits its per-cycle stream budget between two frontiers:\n *\n * - **lagging** — newly subscribed or behind streams catching up.\n * - **leading** — actively-processing streams at the head of the log.\n *\n * After each cycle, this helper looks at how many events were actually\n * handled in each frontier and shifts the next cycle's split toward\n * whichever frontier had the higher per-stream throughput. The result is\n * clamped to `[0.2, 0.8]` so neither frontier can be starved.\n *\n * @internal\n */\n\nimport type { HandleResult } from \"./drain-cycle.js\";\n\n/** Floor / ceiling for the lag-to-lead ratio so neither frontier starves. */\nconst RATIO_MIN = 0.2;\nconst RATIO_MAX = 0.8;\n/** Default ratio when no events were handled in either frontier. */\nconst RATIO_DEFAULT = 0.5;\n\n/**\n * Compute the next lag-to-lead ratio from the cycle's handled events and\n * the frontier sizes used to claim them. Returns `RATIO_DEFAULT` when no\n * progress was made (nothing to base a decision on).\n */\nexport function compute_lag_lead_ratio(\n handled: ReadonlyArray<HandleResult>,\n lagging: number,\n leading: number\n): number {\n let lagging_handled = 0;\n let leading_handled = 0;\n for (const { lease, handled: count } of handled) {\n if (lease.lagging) lagging_handled += count;\n else leading_handled += count;\n }\n const lagging_avg = lagging > 0 ? lagging_handled / lagging : 0;\n const leading_avg = leading > 0 ? leading_handled / leading : 0;\n const total = lagging_avg + leading_avg;\n if (total === 0) return RATIO_DEFAULT;\n return Math.max(RATIO_MIN, Math.min(RATIO_MAX, lagging_avg / total));\n}\n","/**\n * @module drain\n * @category Internal\n *\n * Pipeline operations consumed by the drain/correlate loop. Each op is a\n * single async step the orchestrator invokes per drain cycle:\n *\n * - `claim` — atomically discover and lock streams for processing\n * - `fetch` — read events for each leased stream\n * - `ack` — release leases for successfully handled streams\n * - `block` — flag leases that exceeded the retry budget\n * - `subscribe` — register newly correlated streams with the store\n *\n * This module exposes only the bare implementations as plain async functions,\n * mirroring the shape of {@link \"event-sourcing\"}. Trace decoration is\n * layered on top in {@link \"tracing\"} and selected by the orchestrator at\n * construction time. No tracing imports here.\n *\n * @internal\n */\n\nimport { store } from \"../ports.js\";\nimport type {\n BlockedLease,\n Committed,\n Fetch,\n Lease,\n Schemas,\n} from \"../types/index.js\";\nimport { is_literal_source } from \"../utils.js\";\n\n/** @internal */\nexport interface DrainOps<TEvents extends Schemas> {\n claim: typeof claim;\n fetch: typeof fetch<TEvents>;\n ack: typeof ack;\n block: typeof block;\n subscribe: typeof subscribe;\n}\n\nexport const claim = (\n lagging: number,\n leading: number,\n by: string,\n millis: number,\n lane?: string\n): Promise<Lease[]> => store().claim(lagging, leading, by, millis, lane);\n\nexport async function fetch<TEvents extends Schemas>(\n leased: Lease[],\n eventLimit: number\n): Promise<Fetch<TEvents>> {\n return Promise.all(\n leased.map(async ({ stream, source, at, lagging }) => {\n const events: Committed<TEvents, keyof TEvents>[] = [];\n // A literal `source` fetches with `stream_exact` so an exact name\n // like \"s1\" reads only \"s1\" — never a sibling prefix \"s12\". A\n // pattern source (e.g. `^(A|B)$`) stays a regex query, matching the\n // same streams the has-work probe claimed it for.\n const stream_exact =\n source !== undefined && is_literal_source(source) ? true : undefined;\n await store().query<TEvents>((e) => events.push(e), {\n stream: source,\n stream_exact,\n after: at,\n limit: eventLimit,\n });\n return { stream, source, at, lagging, events } as const;\n })\n );\n}\n\n// Finalize: acks and defers in one atomic store call. Leases\n// carrying `due` are deferred, the rest acked — a failed finalize lands\n// nothing, and redelivery covers every outcome uniformly.\nexport const ack = (leases: Lease[]): Promise<Lease[]> => store().ack(leases);\n\nexport const block = (leases: BlockedLease[]): Promise<BlockedLease[]> =>\n store().block(leases);\n\nexport const subscribe = (\n streams: Array<{\n stream: string;\n source?: string;\n priority?: number;\n lane?: string;\n }>\n): Promise<{ subscribed: number; watermark: number }> =>\n store().subscribe(streams);\n","/**\n * @module event-sourcing\n * @category Internal\n *\n * Pure event-sourcing primitives: `snap` persists state checkpoints, `load`\n * reconstructs state by folding events through reducers, and `action`\n * validates an action, runs invariants, emits events, and commits them\n * atomically. `tombstone` commits the close-the-books guard with optimistic\n * concurrency.\n *\n * These are the bare implementations — observability is layered on top in\n * {@link \"tracing\"} and wired by the orchestrator at construction time.\n * No tracing imports here, no module-level mutable state.\n *\n * @internal\n */\n\nimport { type Patch, patch } from \"@rotorsoft/act-patch\";\nimport { cache, log, SNAP_EVENT, store, TOMBSTONE_EVENT } from \"../ports.js\";\nimport {\n ConcurrencyError,\n InvariantError,\n StreamClosedError,\n} from \"../types/errors.js\";\nimport type {\n Committed,\n Correlator,\n DoOptions,\n Emitted,\n EventMeta,\n EventSource,\n LoadTarget,\n ScanOptions,\n ScanResult,\n Schema,\n Schemas,\n Snapshot,\n State,\n Target,\n} from \"../types/index.js\";\nimport { sleep, validate } from \"../utils.js\";\nimport { compute_backoff_delay } from \"./backoff.js\";\nimport { default_correlator } from \"./correlator.js\";\n\n/**\n * The reduction pipeline names three distinct things, and each word means\n * exactly one of them:\n *\n * - a **reducer** is a state's `.patch()` handler — it takes one event and\n * returns a {@link Patch} *partial*;\n * - a **patch step** ({@link bare_patch} / {@link validating_patch}) merges\n * that partial into the current state, yielding the next full state;\n * - the **fold** is the loop that applies the patch step across a stream's\n * events (the reader loop in {@link load} / {@link action}, and the\n * projection engine in {@link \"projection-fold\"}).\n *\n * `PatchFn` is the per-event patch step. The fold loop calls one of two\n * implementations, selected **once** at construction (in\n * {@link \"tracing\".build_es}) — never branched per event:\n *\n * - {@link bare_patch} — the default. Literally `patch(state, partial)`,\n * no wrapper. This is the pre-ACT-1238 hot path, byte-for-byte.\n * - {@link validating_patch} — the opt-in `ActOptions.validateFoldedState`\n * path. Merges, then parses the merged full state against the state's\n * declared Zod schema.\n *\n * The `me`/`event` arguments are unused by the bare implementation but\n * carried on the shared signature so the fold loop is call-shape-identical\n * regardless of which patch step was selected — the validating\n * implementation needs them to name the failing reduction.\n *\n * @internal\n */\nexport type PatchFn = <\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n me: State<TState, TEvents, TActions>,\n state: TState,\n partial: Readonly<Patch<TState>>,\n event: Committed<TEvents, keyof TEvents>\n) => TState;\n\n/**\n * The default patch step: a bare `patch()` merge with no wrapper and no\n * branch. The off-path is byte-for-byte the pre-ACT-1238 reduction, so an\n * app that leaves `validateFoldedState` off pays nothing — not even a\n * comparison.\n *\n * @internal\n */\nexport const bare_patch: PatchFn = (_me, state, partial) =>\n patch(state, partial) as typeof state;\n\n/**\n * The opt-in patch step (ACT-1238): merge the partial into state, then\n * parse the merged full state against the owning state's declared Zod\n * schema. A reducer that produces schema-violating state (the calculator\n * divide-by-zero NaN class, #1230) fails here, at the triggering event,\n * instead of propagating and surfacing hops later as a confusing\n * downstream error.\n *\n * The `target` string names the state and the triggering event\n * (`\"<state>.<event>#<id>\"`) so the resulting {@link ValidationError}\n * points straight at the reduction that produced bad state. A debugging /\n * CI aid, not a production guard — selected only when the operator opts\n * in.\n *\n * @internal\n */\nexport const validating_patch: PatchFn = (me, state, partial, event) => {\n const next = patch(state, partial) as typeof state;\n return validate(\n `${me.name}.${String(event.name)}#${event.id}`,\n next,\n me.state\n );\n};\n\n/**\n * Default per-batch row count for the {@link scan} pagination loop\n * (ACT-1133). Callers override via {@link ScanOptions.batch_size}.\n *\n * @internal\n */\nconst DEFAULT_BATCH = 500;\n\n/**\n * Internal action signature seen by the orchestrator — the {@link Correlator}\n * is bound at `build_es` time, so callers don't pass it through.\n *\n * @internal\n */\nexport type BoundAction = <\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TKey extends keyof TActions,\n>(\n me: State<TState, TEvents, TActions>,\n action: TKey,\n target: Target,\n payload: Readonly<TActions[TKey]>,\n options?: DoOptions<TEvents>\n) => Promise<Snapshot<TState, TEvents>[]>;\n\n/** @internal */\nexport interface EsOps {\n snap: typeof snap;\n load: typeof load;\n action: BoundAction;\n tombstone: typeof tombstone;\n}\n\n/**\n * Event sourcing utilities for snapshotting, loading, and committing actions/events.\n * Used internally by Act and state machines.\n */\n\n/**\n * Saves a snapshot of the state to the store.\n *\n * Snapshots are used to optimize state reconstruction for aggregates with long event streams.\n *\n * @template TState The type of state\n * @template TEvents The type of events\n * @param snapshot The snapshot to save\n * @returns Promise that resolves when the snapshot is saved\n *\n * @example\n * await snap(snapshot);\n */\nexport async function snap<TState extends Schema, TEvents extends Schemas>(\n snapshot: Snapshot<TState, TEvents>\n): Promise<Committed<TEvents, keyof TEvents> | undefined> {\n const { id, stream, name, meta, version } = snapshot.event!;\n try {\n const [committed] = await store().commit(\n stream,\n [{ name: SNAP_EVENT, data: snapshot.state }],\n {\n correlation: meta.correlation,\n causation: { event: { id, name: name as string, stream } },\n },\n version // IMPORTANT! - state events are committed right after the snapshot event\n );\n return committed as Committed<TEvents, keyof TEvents>;\n } catch (error) {\n // Swallow by design — a failed snapshot must never fail the action.\n // But surface an operator signal: a persistently failing snapshot\n // write silently degrades every cold start to full replay.\n const reason = error instanceof Error ? error.message : String(error);\n log().warn(\n `Snapshot write failed on stream \"${stream}\": ${reason} — cold starts will replay full history until snapshots succeed.`\n );\n }\n}\n\n/**\n * Commits a tombstone event with optimistic concurrency, returning the\n * committed record on success or `undefined` if the stream moved past\n * `expectedVersion` (concurrent write detected). Other store errors\n * propagate.\n *\n * Used by `close()` to guard a stream while archive/truncate runs:\n * subsequent `action()` calls see the tombstone at head and reject with\n * {@link StreamClosedError} until the close completes.\n *\n * @internal\n */\nexport async function tombstone(\n stream: string,\n expectedVersion: number,\n correlation: string\n): Promise<Committed<Schemas, keyof Schemas> | undefined> {\n try {\n const [committed] = await store().commit(\n stream,\n [{ name: TOMBSTONE_EVENT, data: {} }],\n { correlation, causation: {} },\n expectedVersion\n );\n return committed;\n } catch (error) {\n if (error instanceof ConcurrencyError) return undefined;\n throw error;\n }\n}\n\n/**\n * Per-event blocker check. Categories:\n *\n * - **Negative `version`** — versions are unsigned in the framework\n * contract.\n * - **Malformed `created`** — `event.created` must be a valid Date\n * instance. Restore sources stream parsed events; the orchestrator\n * trusts the caller's iterator did the parsing.\n *\n * Cross-event invariants (duplicate ids, per-stream version gaps) are\n * not the validator's job — DB `UNIQUE(stream, version)` catches\n * duplicates at commit time, and gap detection is a caller-specific\n * policy (partial backups intentionally have gaps).\n *\n * Extension point: per-event Zod schema validation against the active\n * registry will land here — the source-side check is the right layer\n * for it (catches malformed payloads before the sink transaction\n * opens), and adding it keeps the per-event blocker contract in one\n * place.\n *\n * @internal\n */\nfunction is_valid(event: Committed<Schemas, keyof Schemas>): boolean {\n if (event.version < 0) return false;\n if (!(event.created instanceof Date) || Number.isNaN(event.created.getTime()))\n return false;\n return true;\n}\n\n/**\n * Scan a restore source event by event. Owns pagination, validation,\n * the `drop_snapshots` filter, the `on_progress` callback, and the\n * causation remap; adapters supply only the per-event insert\n * `callback` via the driver pattern (see {@link Store.restore}).\n *\n * Walks the source in chunks of {@link BATCH} via the existing\n * `EventSource.query` interface — `limit: BATCH` and `after: <last\n * id seen>` per batch (ACT-1133). Stores that respect `limit`\n * (`PostgresStore`) return at most `BATCH` rows per call; sources\n * that ignore the filter (`CsvFile`) stream everything in one call\n * and the loop exits after the first batch when `got > BATCH`. The\n * source's own per-event `await Promise.resolve(callback(event))`\n * provides backpressure — no separate mailbox needed.\n *\n * Throws on the first invalid event (negative version, malformed\n * `created`) with the running index in the message.\n *\n * Returns the partial {@link ScanResult} (without `duration_ms`)\n * — {@link Act.restore} wraps the call with its own timing so the\n * duration covers transaction setup and commit, not just iteration.\n *\n * @internal\n */\nexport async function scan(\n source: EventSource,\n opts: ScanOptions = {},\n callback?: (event: Committed<Schemas, keyof Schemas>) => Promise<number>\n): Promise<Omit<ScanResult, \"duration_ms\">> {\n const {\n drop_snapshots = false,\n drop_closed_streams = false,\n on_progress,\n event_migrations,\n stream_rename,\n } = opts;\n const limit = opts.batch_size ?? DEFAULT_BATCH;\n const id_map = new Map<number, number>();\n let kept = 0;\n let dropped_snaps = 0;\n let dropped_closed = 0;\n let migrated_count = 0;\n let processed = 0;\n let at: number | undefined;\n\n // Pre-pass for `drop_closed_streams` (ACT-1126). Walk the source\n // once with a tombstone-name filter to collect closed streams. PG\n // honors the filter and only the tombstone events come back; sources\n // that ignore the filter (CsvFile) stream all events but we cheaply\n // pick out the tombstones in the callback. Either way the cost is\n // one extra walk, paid only when the operator opts in.\n const closed_streams = new Set<string>();\n if (drop_closed_streams) {\n await source.query<Schemas>(\n (e) => {\n if (e.name === TOMBSTONE_EVENT) closed_streams.add(e.stream);\n },\n { names: [TOMBSTONE_EVENT] }\n );\n }\n\n // Probe the source for the highest id once up front. On indexed\n // stores (PostgresStore, SqliteStore) `{ backward: true, limit: 1 }`\n // is an index-only seek — O(1) on the (id) index. Sources that\n // ignore the filter (CsvFile) stream every event from this one\n // call; we detect that via the returned count and leave max_id\n // undefined rather than reporting an unreliable value.\n let max_id: number | undefined;\n const probed = await source.query<Schemas>(\n (e) => {\n max_id = e.id;\n },\n { backward: true, limit: 1 }\n );\n if (probed !== 1) max_id = undefined;\n\n while (true) {\n let got = 0;\n let id: number | undefined;\n\n await source.query<Schemas>(\n async (event) => {\n got++;\n id = event.id;\n processed++;\n if (!is_valid(event))\n throw new Error(`Invalid event at index ${processed}`);\n if (on_progress) on_progress({ processed, id: event.id, max_id });\n if (drop_snapshots && event.name === SNAP_EVENT) {\n dropped_snaps++;\n return;\n }\n if (\n closed_streams.has(event.stream) &&\n event.name !== TOMBSTONE_EVENT\n ) {\n // Drop pre-close events but KEEP the tombstone — it's what\n // makes the stream \"closed\" in the rebuilt store. Without\n // it, a future `app.do(...)` against this stream name would\n // succeed because nothing gates it.\n dropped_closed++;\n return;\n }\n // Migration overlay (ACT-1126): rename + schema-guarded data\n // transform, then optional stream rename. Applied BEFORE the\n // causation remap so the id_map (keyed by source id) stays\n // valid and migrated events land at the new name/data with\n // their causation chains intact.\n let migrated: typeof event = event;\n const migration = event_migrations?.[event.name as string];\n if (migration) {\n const old_data = migration.from_schema.parse(event.data);\n const new_data = migration.migrate(old_data);\n migration.to_schema.parse(new_data);\n migrated = {\n ...event,\n name: migration.to as typeof event.name,\n data: new_data as any,\n };\n migrated_count++;\n }\n if (stream_rename) {\n const renamed = stream_rename(migrated.stream);\n if (renamed !== migrated.stream)\n migrated = { ...migrated, stream: renamed };\n }\n if (!callback) {\n kept++;\n return;\n }\n // Causation remap — rewrite `meta.causation.event.id` to the\n // new id space if the source pointed at an earlier event's\n // old id.\n let remapped = migrated;\n const caused_by = migrated.meta.causation.event?.id;\n if (caused_by !== undefined) {\n const new_caused_by = id_map.get(caused_by);\n if (new_caused_by !== undefined && new_caused_by !== caused_by) {\n // Spread `migrated`, not the original `event` (ACT-1192).\n // Migration + stream_rename already ran above; rebuilding from\n // `event` here would revert the new name/data/stream for any\n // event whose causation id shifted — silently undoing the\n // migration for most rows after the first id shift.\n remapped = {\n ...migrated,\n meta: {\n ...migrated.meta,\n causation: {\n ...migrated.meta.causation,\n event: {\n ...migrated.meta.causation.event!,\n id: new_caused_by,\n },\n },\n },\n };\n }\n }\n const new_id = await callback(remapped);\n id_map.set(event.id, new_id);\n kept++;\n },\n { after: at, limit }\n );\n\n // Termination:\n // - got < batch: source honored limit but ran out (also covers\n // got === 0 — past-the-end on a paginating source).\n // - got > batch: source ignored the filter (CsvFile-style). It\n // streamed everything in one call; nothing left to ask for.\n // Otherwise (got === batch): more events may exist; bump and continue.\n if (got !== limit) break;\n at = id;\n }\n\n return {\n kept,\n migrated: migrated_count,\n dropped: {\n closed_streams: dropped_closed,\n snapshots: dropped_snaps,\n },\n };\n}\n\n/**\n * Loads a snapshot of the state from the store by folding events through the\n * state's patch reducers.\n *\n * First checks the cache for a checkpoint, then queries the store for events\n * committed after the cached position. On cache miss, replays from the store\n * (using snapshots if available to avoid full replay).\n *\n * @template TState The type of state\n * @template TEvents The type of events\n * @template TActions The type of actions\n * @param me The state machine definition.\n * @param stream The stream (instance) to load\n * @param callback (Optional) Callback to receive the loaded snapshot as it is built\n * @param asOf (Optional) Time-travel cursor; bypasses the cache.\n * @param actor (Optional) Passed through to the state's `view` delegate\n * when constructing the snapshot.event — semantics are the state's to\n * define (see {@link state}).\n * @returns The snapshot of the loaded state\n *\n * @example\n * const snapshot = await load(Counter, \"counter1\");\n */\nexport async function load<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n me: State<TState, TEvents, TActions>,\n target: LoadTarget,\n callback?: (snapshot: Snapshot<TState, TEvents>) => void,\n patch_fn: PatchFn = bare_patch\n): Promise<Snapshot<TState, TEvents>> {\n const { stream, actor, asOf } = target;\n const time_travel =\n !!asOf && Object.values(asOf).some((v) => v !== undefined);\n const cached = time_travel ? undefined : await cache().get<TState>(stream);\n const cache_hit = !!cached;\n let state = cached?.state ?? (me.init ? me.init() : ({} as TState));\n let patches = cached?.patches ?? 0;\n let snaps = cached?.snaps ?? 0;\n // replayed counts events processed by THIS load only (snap or patch);\n // distinct from `patches` (the snap-distance accumulator carried over\n // from the cache).\n let replayed = 0;\n let event: Committed<TEvents, keyof TEvents> | undefined;\n\n await store().query<TEvents>(\n (raw) => {\n event = me.view(raw, actor);\n if (event.name === SNAP_EVENT) {\n state = event.data as TState;\n snaps++;\n patches = 0;\n replayed++;\n } else if (me.patch[event.name]) {\n state = patch_fn(me, state, me.patch[event.name](event, state), event);\n patches++;\n replayed++;\n } else if (event.name !== TOMBSTONE_EVENT) {\n // Unknown event — not in this state's reducer map. Causes:\n // deleted/renamed event in a versioned schema, load() called with\n // the wrong state, or stream contamination. Skipping silently\n // would corrupt replay; warn so the operator can investigate.\n log().warn(\n `Skipping unknown event \"${String(event.name)}\" on stream \"${stream}\" (id=${event.id}) — no reducer in state \"${me.name}\"`\n );\n }\n callback?.({\n event,\n state,\n version: event.version,\n id: event.id,\n patches,\n snaps,\n cache_hit,\n replayed,\n });\n },\n {\n stream,\n stream_exact: true,\n // The snapshot resume floor is a current-state optimization: it only\n // holds when the load has no window of its own. `time_travel` already\n // captures that (any `asOf` bound set), so request `with_snaps` only for\n // a non-time-travel cold load — a bounded load full-scans real events\n // under its `asOf` filter. This is the single floor-eligibility decision\n // for the whole system; the stores apply the floor whenever asked and\n // never re-derive it (RFC 1274).\n //\n // The warm path resumes from `after`, and MUST also carry `with_snaps`\n // (#1345): `after` and `with_snaps` are independent store conditions —\n // `after` bounds the scan (id > cached.event_id), `with_snaps` keeps\n // `__snapshot__` rows in the result. A stale (lagging/cross-process)\n // cache checkpoint can sit below a newer `__snapshot__` boundary, and a\n // windowed close (`app.close`/`.autocloses({keep})`) may have pruned the\n // domain events between the checkpoint and that snapshot. Without\n // `with_snaps` the rebaselining snapshot is filtered out and the fold\n // silently applies the surviving tail on top of stale state (wrong\n // count, yet `version` still reports the true head — the concurrency\n // guard passes). With it, the snapshot in the after-window rebaselines\n // the fold; when no snapshot falls in the window it is a no-op.\n ...(cached\n ? { after: cached.event_id, with_snaps: true }\n : { ...(time_travel ? {} : { with_snaps: true }), ...asOf }),\n }\n );\n\n // Populate the cache when this load actually processed events. Without\n // this, read-heavy paths (UI loops calling load() many times between\n // commits) miss the cache forever — only action() would ever warm it.\n // No race-protection re-check needed: the cache is a state checkpoint\n // at (version, event_id), and any subsequent load queries past\n // event_id (with `with_snaps`, so a rebaselining snapshot above the\n // checkpoint is still folded even after a windowed close pruned the\n // events between them — #1345), picks up missed events, and replays — so\n // an \"older\" cache write from a concurrent slower load is self-correcting\n // on next access. Time-travel loads bypass cache entirely and skip this too.\n //\n // Skip the write when the replayed head is the tombstone (ACT-1188).\n // During the close guard window (tombstone committed, truncate pending)\n // a cold load replays real events + the tombstone, so `replayed > 0`.\n // Caching here would store a checkpoint at the tombstone's (version,\n // event_id) with no `event` on the entry — the next `action()` would\n // then get a warm hit where `snapshot.event` is undefined, its\n // cold-path tombstone check (`snapshot.event?.name === TOMBSTONE_EVENT`)\n // would go vacuously false, and a commit could land past the tombstone\n // that the eventual truncate deletes. Leaving the cache cold keeps that\n // check live on every subsequent load.\n const head_is_tombstone = event?.name === TOMBSTONE_EVENT;\n if (\n replayed > 0 &&\n !time_travel &&\n event &&\n !me.pii_aware &&\n !head_is_tombstone\n ) {\n // Fire-and-forget the checkpoint write, mirroring action() (ACT-1206):\n // the state is already correctly computed, so a transient failure in a\n // remote-backed Cache (e.g. a Redis blip) must not fail the read — that\n // would break plain reads, reaction bound_load dispatches, and the fold\n // engine's first-sight load. The cache is self-correcting: a subsequent\n // load queries past `event_id`, replays what it missed, and re-warms.\n await cache()\n .set(stream, {\n stream,\n state,\n version: event.version,\n event_id: event.id,\n patches,\n snaps,\n })\n .catch((err) => log().error(err));\n }\n\n return {\n event,\n state,\n version: event?.version ?? cached?.version ?? -1,\n // Head event id, captured atomically with `state`: the last replayed\n // event's id on a cache miss, or the cached checkpoint's event_id on a\n // warm hit with no new events. Consumers read this instead of a\n // separate cache lookup that could race a concurrent commit (ACT-1204).\n id: event?.id ?? cached?.event_id ?? -1,\n patches,\n snaps,\n cache_hit,\n replayed,\n };\n}\n\n/**\n * Executes an action and emits an event to be committed by the store.\n *\n * Validates the action, applies business invariants, emits events, and\n * commits them to the event store. When the action's\n * {@link ActionOptions} declare a retry budget, the orchestrator owns\n * the loop on {@link ConcurrencyError}: cache is invalidated, optional\n * `backoff` delay is applied, and the action re-runs from `load`. Any\n * other error rethrows immediately and does not consume the budget.\n *\n * Reactions skip optimistic concurrency (commit below passes\n * `undefined` as `expectedVersion` when `reactingTo` is set), so\n * `ConcurrencyError` cannot fire on the reaction-driven path — the\n * loop is naturally a no-op there.\n *\n * @template TState The type of state\n * @template TEvents The type of events\n * @template TActions The type of action_schemas\n * @template TKey The type of action to execute\n * @param me The state machine definition\n * @param action The action to execute\n * @param target The target (stream, actor, etc.)\n * @param payload The payload of the action\n * @param options Per-call dispatch options ({@link DoOptions}) —\n * `reactingTo` to thread correlation, `correlator` to override the\n * framework or orchestrator-level correlator for this call only.\n * @returns The snapshot of the committed event\n *\n * @example\n * const snapshot = await action(Counter, \"increment\", { stream: \"counter1\", actor }, { by: 1 });\n */\nexport async function action<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TKey extends keyof TActions,\n>(\n me: State<TState, TEvents, TActions>,\n action: TKey,\n target: Target,\n payload: Readonly<TActions[TKey]>,\n options?: DoOptions<TEvents>,\n patch_fn: PatchFn = bare_patch\n): Promise<Snapshot<TState, TEvents>[]> {\n const { stream, expectedVersion, actor } = target;\n if (!stream) throw new Error(\"Missing target stream\");\n const reactingTo = options?.reactingTo;\n const correlator = options?.correlator ?? default_correlator;\n\n const validated = validate(action as string, payload, me.actions[action]);\n\n const opts = me.options?.[action];\n const max_retries = opts?.maxRetries ?? 0;\n\n for (let attempt = 0; ; attempt++) {\n try {\n const snapshot = await load(\n me,\n { stream, actor: target.actor },\n undefined,\n patch_fn\n );\n if (snapshot.event?.name === TOMBSTONE_EVENT)\n throw new StreamClosedError(stream);\n // snapshot.version is the head version even on a warm cache hit,\n // where snapshot.event is undefined — using the event would\n // silently drop the optimistic guard for every cached stream.\n // A brand-new stream (-1) stays unguarded: creations append.\n const expected =\n expectedVersion ??\n (snapshot.version >= 0 ? snapshot.version : undefined);\n\n if (me.given) {\n const invariants = me.given[action] || [];\n invariants.forEach(({ valid, description }) => {\n if (!valid(snapshot.state, actor))\n throw new InvariantError(\n action,\n validated,\n target,\n snapshot,\n description\n );\n });\n }\n\n const result = me.on[action](validated, snapshot, target);\n if (!result) return [snapshot];\n\n // An empty array means no events were emitted\n if (Array.isArray(result) && result.length === 0) {\n return [snapshot];\n }\n\n const tuples = Array.isArray(result[0])\n ? (result as Emitted<TEvents>[]) // array of tuples\n : ([result] as Emitted<TEvents>[]); // single tuple\n\n const valid = tuples.map(([name, data]) => ({\n name,\n data: validate(name as string, data, me.events[name]),\n }));\n const emitted = valid.map((e) => me.message(e));\n\n const meta: EventMeta = {\n correlation:\n reactingTo?.meta.correlation ||\n correlator({\n action: action as string,\n state: me.name,\n stream,\n actor: target.actor,\n }),\n causation: {\n action: {\n name: action as string,\n ...target,\n // payload intentionally omitted from causation metadata —\n // callers correlate via the correlation id when they need it.\n },\n event: reactingTo\n ? {\n id: reactingTo.id,\n name: reactingTo.name as string,\n stream: reactingTo.stream,\n }\n : undefined,\n },\n };\n\n let committed: Committed<TEvents, keyof TEvents>[];\n try {\n committed = await store().commit(\n stream,\n emitted,\n meta,\n // Reactions skip optimistic concurrency: they always append against the\n // current head. Stream leasing already serializes concurrent reactions,\n // and forcing version checks here would turn ordinary catch-up into\n // spurious retries.\n reactingTo ? undefined : expected\n );\n } catch (error) {\n // Invalidate cache on concurrency errors — cached state is stale.\n //\n // Contained and NOT awaited, matching every other cache write on this\n // path (the load checkpoint, the action checkpoint, the gapped-commit\n // invalidate): a transient failure in a remote-backed Cache must not\n // fail the operation. Awaiting it unguarded here did two kinds of\n // damage (#1438). The caller got the cache's error instead of the\n // `ConcurrencyError`, so transports mapped a Redis blip to 500 rather\n // than 412. Worse, the substituted error failed the\n // `instanceof ConcurrencyError` test in the retry loop below, so a\n // conflict that would have resolved on reload+retry became a\n // permanent failure with the work lost.\n //\n // The invalidate is defensive anyway: the cache is self-correcting,\n // since a stale checkpoint is re-folded from `after: event_id`.\n if (error instanceof ConcurrencyError) {\n cache()\n .invalidate(stream)\n .catch((err) => log().error(err));\n }\n throw error;\n }\n\n let { state, patches } = snapshot;\n const snapshots = committed.map((row, i) => {\n // Actions originate from the caller — they already hold the\n // plaintext payload they sent. No view/gate round-trip is\n // useful; the reducer and the returned snapshot see the\n // pre-split event directly. pii_split (in `me.message`) above\n // is the only PII operation on the action path.\n const event = { ...row, data: valid[i].data };\n const p = me.patch[event.name](event, state);\n state = patch_fn(me, state, p, event);\n patches++;\n return {\n event,\n state,\n version: event.version,\n id: event.id,\n patches,\n snaps: snapshot.snaps,\n patch: p,\n cache_hit: snapshot.cache_hit,\n replayed: snapshot.replayed,\n };\n });\n\n // fire and forget snaps\n const last = snapshots.at(-1)!;\n // Guardless commits (reactions append at head by design) can land\n // past events this fold never saw. A gapped fold must not become\n // a snapshot event or a cache entry — both would lie at the head\n // position. Contiguity is cheap to prove: the first committed\n // version extends the loaded one.\n const contiguous = committed[0].version === snapshot.version + 1;\n const snapped = contiguous && me.snap?.(last);\n\n // Persist the snapshot before caching. Awaited on purpose: the\n // snapshot event occupies the next version slot, so a follow-up\n // action loading a pre-snap checkpoint from the cache would collide\n // with the framework's own bookkeeping. Caching the snap checkpoint\n // before the action returns keeps sequential callers from ever\n // seeing a conflict they didn't cause. Failures are still\n // swallowed inside snap() — the action never fails on it, and the\n // cache then keeps the pre-snap checkpoint, which stays correct.\n const snap_event = snapped ? await snap(last) : undefined;\n\n // #861: pii-aware states (any event declaring `sensitive(...)`\n // fields) never populate the snapshot cache — state evolves from\n // the actor-gated event view, so the cached state would vary by\n // caller. Pure states cache normally.\n // Fire-and-forget — log but don't fail the action on cache write errors\n // (e.g., transient network failures in a custom Cache adapter).\n if (!me.pii_aware) {\n if (contiguous)\n cache()\n .set<TState>(stream, {\n stream,\n state: last.state,\n version: snap_event?.version ?? last.event.version,\n event_id: snap_event?.id ?? last.event.id,\n patches: snap_event ? 0 : last.patches,\n snaps: snap_event ? last.snaps + 1 : last.snaps,\n })\n .catch((err) => log().error(err));\n // A gapped entry would sit at the head position with unfolded\n // events baked in — drop the checkpoint and let the next load\n // replay to truth instead.\n else\n cache()\n .invalidate(stream)\n .catch((err) => log().error(err));\n }\n\n return snapshots;\n } catch (error) {\n if (!(error instanceof ConcurrencyError)) throw error;\n // A caller-pinned expectedVersion is a fixed target: every retry\n // reloads and re-commits against the SAME pinned version, so the\n // conflict is guaranteed to recur — retrying only burns the budget\n // and sleeps out the backoff before surfacing the same terminal\n // error. Rethrow immediately (ACT-1208). The retry loop exists to\n // absorb races on framework-derived versions (a concurrent writer\n // advanced the head), where the reload picks up the new head\n // version and the next attempt can succeed.\n if (expectedVersion !== undefined) throw error;\n if (attempt >= max_retries) throw error;\n if (opts?.backoff) {\n const delay_ms = compute_backoff_delay(attempt, opts.backoff);\n if (delay_ms > 0) await sleep(delay_ms);\n }\n }\n }\n}\n","/**\n * @module backoff\n * @category Internal\n *\n * Per-reaction retry backoff delay computation. Pure function — keeps\n * `DrainController` and `reactions._finalize` testable in isolation.\n *\n * @internal\n */\n\nimport type { BackoffOptions } from \"../types/action.js\";\n\n// The `BackoffOptions` config schema + resolver live in `./config.ts` (the\n// single home for every builder-facing config bag). This module keeps only\n// the runtime delay math, which stays hot-path and dependency-free.\n\n/**\n * Compute the wall-clock delay (in ms) to wait before the next attempt on\n * a stream whose handler just failed.\n *\n * @param retry - The lease's `retry` counter at finalize time. `0` is the\n * first attempt that failed; `1` is after one retry; etc.\n * @param opts - Per-reaction backoff config. Returns `0` when undefined.\n * @returns Non-negative integer milliseconds. Always `0` when `opts` is\n * undefined or `baseMs <= 0`.\n */\nexport function compute_backoff_delay(\n retry: number,\n opts: BackoffOptions | undefined\n): number {\n if (!opts || opts.baseMs <= 0) return 0;\n const r = Math.max(0, retry);\n let delay: number;\n switch (opts.strategy) {\n case \"fixed\":\n delay = opts.baseMs;\n break;\n case \"linear\":\n delay = opts.baseMs * (r + 1);\n break;\n case \"exponential\":\n delay = opts.baseMs * 2 ** r;\n if (opts.maxMs !== undefined) delay = Math.min(delay, opts.maxMs);\n break;\n default: {\n // Unreachable once options pass `resolveBackoffConfig` at their\n // declaration site. Defensive so the pure function is total and can\n // never emit `NaN` from an unvalidated strategy — throw instead.\n const _never: never = opts.strategy;\n throw new Error(`unknown backoff strategy: ${String(_never)}`);\n }\n }\n if (opts.jitter) delay = delay * (0.5 + Math.random());\n return Math.max(0, Math.floor(delay));\n}\n","/**\n * @module tracing\n * @category Internal\n *\n * Centralized observability for the framework's internal pipelines.\n *\n * Trace decorators wrap a bare implementation with `logger.trace(...)` calls\n * at well-defined moments — entry points for {@link \"event-sourcing\"} (`load`,\n * `snap`, `action`) and exit points for the {@link \"drain\"} pipeline (`claim`,\n * `fetch`, `ack`, `block`, `subscribe`). `action` carries both an entry log\n * and a post-commit log to preserve the diagnostic value of the historical\n * mid-function trace points.\n *\n * Output styles:\n * - **Pretty mode** (`config().env !== \"production\"`) — event-sourcing logs\n * show only the colored target body (color carries the operation/phase),\n * drain logs keep a colored caption.\n * - **Plain mode** (production / log aggregators) — every log gets a textual\n * prefix; event-sourcing uses `caption: body`, drain uses `caption body`.\n *\n * The two factories — {@link build_es} and {@link build_drain} — let the\n * orchestrator choose bare or traced variants once at `.build()` time based\n * on the configured log level. Outside this module, no other source file\n * imports tracing primitives.\n *\n * @internal\n */\n\nimport { config } from \"../config.js\";\nimport type { AsOf, Correlator, Logger, Schemas } from \"../types/index.js\";\nimport { default_correlator } from \"./correlator.js\";\nimport type { DrainOps } from \"./drain.js\";\nimport * as drain from \"./drain.js\";\nimport type { EsOps, PatchFn } from \"./event-sourcing.js\";\nimport * as es from \"./event-sourcing.js\";\n\ntype AsyncFn = (...args: any[]) => Promise<any>;\n\nconst PRETTY = config().env !== \"production\";\n\n// 256-color codes for distinctive, theme-friendly hues\nconst C_BLUE = \"\\x1b[38;5;39m\"; // vivid sky blue (action)\nconst C_ORANGE = \"\\x1b[38;5;208m\"; // true orange (committed)\nconst C_GREEN = \"\\x1b[38;5;42m\"; // emerald (load)\nconst C_MAGENTA = \"\\x1b[38;5;165m\"; // bright magenta (snap)\nconst C_DRAIN = \"\\x1b[38;5;244m\"; // muted gray for all drain ops\n// load-trace cache marker shades — distinguishable from C_GREEN body color\nconst C_HIT = \"\\x1b[38;5;82m\"; // lime — fast path, blends visually\nconst C_MISS = \"\\x1b[38;5;220m\"; // amber — non-trivial work happened\nconst C_RESET = \"\\x1b[0m\";\n\n/**\n * Format an event-sourcing trace line. Pretty mode renders just the colored\n * body (the color is the cue for which op/phase fired); plain mode prepends\n * `caption: ` so log aggregators stay readable without ANSI.\n */\nconst es_caption = (caption: string, color: string, body: string): string =>\n PRETTY ? `${color}${body}${C_RESET}` : `${caption}: ${body}`;\n\n/**\n * Format a drain-pipeline caption. Drain logs keep a `>>` marker for easy\n * spotting in mixed log streams, plus a `caption` (past tense — every drain\n * trace fires on exit). All drain ops share one color (gray) so the pipeline\n * reads as a single channel; the caption disambiguates the phase. Lane\n * (ACT-1103) is appended in lilac, unwrapped, when set and non-default,\n * so the operator's eye lands on the lane name without parsing per-stream\n * detail. Per-stream `@at/retry` and fetched event lists are muted via\n * {@link dim} so the stream name itself reads loudest.\n */\nconst C_LANE = \"\\x1b[38;5;183m\"; // lilac — distinct from gray drain + drain ops\nconst C_DIM = \"\\x1b[38;5;240m\"; // dim gray — dimmer than C_DRAIN\nconst C_ERR = \"\\x1b[38;5;196m\"; // bright red — block marker\nconst C_STREAM = \"\\x1b[38;5;226m\"; // bright yellow — target stream names in drain/correlate traces\n\n/** Wrap with the muted color when pretty mode is on. Plain in production. */\nconst dim = (text: string): string =>\n PRETTY ? `${C_DIM}${text}${C_RESET}` : text;\n\n/** Wrap with a foreground color when pretty mode is on; bare in production. */\nconst hue = (color: string, text: string): string =>\n PRETTY ? `${color}${text}${C_RESET}` : text;\n\nconst drain_caption = (caption: string, lane?: string): string => {\n const show_lane = lane && lane !== \"default\";\n if (PRETTY) {\n const tag = `${C_DRAIN}>> ${caption}${C_RESET}`;\n return show_lane ? `${tag} ${C_LANE}${lane}${C_RESET}` : tag;\n }\n return show_lane ? `>> ${caption} ${lane}` : `>> ${caption}`;\n};\n\n/**\n * Format the cache hit/miss marker for the load trace. In pretty mode the\n * word is colored (lime for hit, amber for miss) and the surrounding\n * `C_GREEN` body color is restored after — embedded ANSI inside `es_caption`'s\n * outer wrap. Plain mode returns the bare word.\n */\nconst cache_marker = (hit: boolean): string => {\n const word = hit ? \"hit\" : \"miss\";\n if (!PRETTY) return word;\n return `${hit ? C_HIT : C_MISS}${word}${C_RESET}${C_GREEN}`;\n};\n\n/**\n * Format the load stats (`v=N replayed=N snaps=N patches=N`) for the load\n * trace. Muted gray in pretty mode so the cache marker reads as the most\n * important cue; plain mode returns the bare text.\n *\n * - `v` — stream head version (the version of the last event applied)\n * - `replayed` — events processed by THIS load past the cache point\n * - `snaps` — cumulative snapshots taken on this stream\n * - `patches` — events since the last snap (snap-policy accumulator)\n */\nconst stats_marker = (\n version: number,\n replayed: number,\n snaps: number,\n patches: number\n): string => {\n const text = `v=${version} replayed=${replayed} snaps=${snaps} patches=${patches}`;\n if (!PRETTY) return text;\n return `${C_DRAIN}${text}${C_RESET}${C_GREEN}`;\n};\n\n/**\n * Format the as-of marker for time-travel loads. Surfaces the active filter\n * fields (before id, created_before/after timestamps, limit) so an operator\n * can tell at a glance which slice was loaded. Empty `asOf` returns \"\" —\n * non-time-travel loads skip the marker entirely.\n */\nconst as_of_marker = (asOf: AsOf | undefined): string => {\n if (!asOf) return \"\";\n const parts: string[] = [];\n if (asOf.before !== undefined) parts.push(`before=${asOf.before}`);\n if (asOf.created_before !== undefined)\n parts.push(`created_before=${asOf.created_before.toISOString()}`);\n if (asOf.created_after !== undefined)\n parts.push(`created_after=${asOf.created_after.toISOString()}`);\n if (asOf.limit !== undefined) parts.push(`limit=${asOf.limit}`);\n return parts.length ? ` (as-of ${parts.join(\" \")})` : \" (as-of)\";\n};\n\n/**\n * Wraps an async function with optional `exit` and `entry` callbacks. Each\n * callback fires at the corresponding phase; both receive the call args, and\n * `exit` additionally receives the resolved result. Used to layer\n * `logger.trace` calls onto bare ops without changing their signatures.\n *\n * @internal\n */\nconst traced = <F extends AsyncFn>(\n inner: F,\n exit?: (result: Awaited<ReturnType<F>>, ...args: Parameters<F>) => void,\n entry?: (...args: Parameters<F>) => void\n): F =>\n (async (...args: Parameters<F>) => {\n entry?.(...args);\n const result = (await inner(...args)) as Awaited<ReturnType<F>>;\n exit?.(result, ...args);\n return result;\n }) as F;\n\n/**\n * Selects bare or traced event-sourcing handlers. Called once by the\n * orchestrator constructor.\n *\n * @internal\n */\nexport function build_es(\n logger: Logger,\n correlator: Correlator = default_correlator,\n patch_fn: PatchFn = es.bare_patch\n): EsOps {\n // Bake the orchestrator-level `correlator` into every `action()` call\n // so EsOps callers don't need to thread it. A per-call\n // `options.correlator` still wins — the orchestrator default fills in\n // only when the caller didn't supply one.\n //\n // ACT-1238: the per-event patch step is selected ONCE by the builder\n // (`act-builder.ts`) — bare vs validating — and passed in here already\n // bound, so this factory stays agnostic to `validateFoldedState`. It\n // just bakes the given `patch_fn` into the load/action closures, so\n // the projection-fold engine and close-cycle callers inherit the same\n // choice without threading anything through their own signatures. The\n // default (`bare_patch`) keeps direct callers on the pre-#1238 path.\n const bound_action: EsOps[\"action\"] = (\n me,\n action_name,\n target,\n payload,\n options\n ) =>\n es.action(\n me,\n action_name,\n target,\n payload,\n { correlator, ...options },\n patch_fn\n );\n const bound_load: EsOps[\"load\"] = (me, target, callback) =>\n es.load(me, target, callback, patch_fn);\n if (logger.level !== \"trace\") {\n return {\n snap: es.snap,\n load: bound_load,\n action: bound_action,\n tombstone: es.tombstone,\n };\n }\n return {\n snap: traced(es.snap, undefined, (snapshot) => {\n logger.trace(\n es_caption(\n \"snap\",\n C_MAGENTA,\n `${snapshot.event!.stream}@${snapshot.event!.version}`\n )\n );\n }),\n load: traced(bound_load, (result, _me, target) => {\n const stats = stats_marker(\n result.version,\n result.replayed,\n result.snaps,\n result.patches\n );\n logger.trace(\n es_caption(\n \"load\",\n C_GREEN,\n `${target.stream}${as_of_marker(target.asOf)} ${cache_marker(result.cache_hit)} ${stats}`\n )\n );\n }),\n action: traced(\n bound_action,\n (snapshots, _me, _action, target) => {\n const committed = snapshots.filter((s) => s.event);\n if (committed.length) {\n logger.trace(\n committed.map((s) => s.event!.data),\n es_caption(\n \"committed\",\n C_ORANGE,\n `${target.stream}.${committed.map((s) => s.event!.name).join(\", \")}`\n )\n );\n }\n },\n (_me, action, target, payload) => {\n logger.trace(\n payload as object,\n es_caption(\"action\", C_BLUE, `${target.stream}.${action}`)\n );\n }\n ),\n tombstone: traced(es.tombstone, (committed, stream) => {\n if (committed)\n logger.trace(\n es_caption(\"tombstoned\", C_ORANGE, `${stream}@${committed.version}`)\n );\n }),\n };\n}\n\n/**\n * Selects bare or traced drain-pipeline ops. Called once by the orchestrator\n * constructor.\n *\n * @internal\n */\nexport function build_drain<TEvents extends Schemas>(\n logger: Logger\n): DrainOps<TEvents> {\n // Cycle-level tracing happens in `DrainController.drain()` via\n // {@link trace_cycle} — claim/fetch/ack/block all flow into one log\n // line per cycle to give the operator a single atomic narrative.\n // `subscribe` stays decorated because it's driven from correlate-\n // cycle (not from run_drain_cycle) and doesn't fit the cycle shape.\n return {\n claim: drain.claim,\n fetch: drain.fetch,\n ack: drain.ack,\n block: drain.block,\n subscribe:\n logger.level !== \"trace\"\n ? drain.subscribe\n : traced(drain.subscribe, (result, streams) => {\n if (!result.subscribed) return;\n // Caption mirrors `drained`: lane in the caption when the\n // whole batch shares a single non-default lane. Mixed-lane\n // batches (rare — different correlated targets resolving\n // to different lanes in one scan) fall back to per-stream\n // `[lane]` tags, default-lane streams stay bare either way.\n const lanes = new Set(streams.map((s) => s.lane ?? \"default\"));\n const uniform_lane =\n lanes.size === 1 ? streams[0]?.lane : undefined;\n const data = streams\n .map(({ stream, lane }) =>\n uniform_lane || !lane || lane === \"default\"\n ? hue(C_STREAM, stream)\n : `${hue(C_STREAM, stream)}${dim(`[${lane}]`)}`\n )\n .join(\" \");\n logger.trace(\n `${drain_caption(\"correlated\", uniform_lane)} ${data}`\n );\n }),\n };\n}\n\n/**\n * Emit one cycle-level drain trace summarizing what happened in a\n * single `run_drain_cycle` pass. Per-stream rendering shape — outcome +\n * post-state anchored on the right:\n *\n * stream<-source [events] ✓ @<acked-at> — full success\n * stream<-source [events] ✗ @<failed-at>/<retry> (error) — total failure → blocked\n * stream<-source [events] ⚠ @<failed-at>/<retry> (error) — total failure → retrying\n * stream<-source [events] ✓ @<acked-at> ✗ @<failed-at>/<retry> (error) — partial then blocked\n * stream<-source [events] ✓ @<acked-at> ⚠ @<failed-at>/<retry> (error) — partial then retrying\n * stream<-source ⊘ @<at>/<retry> — deferred (backoff)\n *\n * Partial-success-then-failure is the dual-outcome case: events\n * 1..K succeeded (watermark advanced to K), event K+1 threw. The\n * trace renders both the lime `✓ @K` and the red/amber `✗`/`⚠ @K+1`\n * on the same line so an operator sees \"we made progress *and* then\n * something broke\" at a glance.\n *\n * Lane prefixes the caption in lilac when non-default. The outcome\n * marker and its adjacent post-state share the marker's color so the\n * eye reads \"outcome + where it landed\" as one unit. Per-stream\n * `[events]` and `(error)` stay dim — secondary context.\n *\n * @internal\n */\nexport function trace_cycle<TEvents extends Schemas>(\n logger: Logger,\n leased: ReadonlyArray<{\n readonly stream: string;\n readonly at: number;\n readonly retry: number;\n readonly lane?: string;\n }>,\n fetched: ReadonlyArray<{\n readonly stream: string;\n readonly source?: string;\n readonly events: ReadonlyArray<{\n readonly id: number;\n readonly name: keyof TEvents;\n }>;\n }>,\n handled: ReadonlyArray<{\n readonly lease: { readonly stream: string };\n readonly error?: string;\n readonly block?: boolean;\n readonly failed_at?: number;\n }>,\n acked: ReadonlyArray<{ readonly stream: string; readonly at: number }>,\n blocked: ReadonlyArray<{ readonly stream: string; readonly error: string }>\n): void {\n if (logger.level !== \"trace\" || !leased.length) return;\n const lane = leased[0]?.lane;\n const fetch_by_stream = new Map(fetched.map((f) => [f.stream, f]));\n const acked_by_stream = new Map(acked.map((a) => [a.stream, a.at]));\n const blocked_by_stream = new Map(blocked.map((b) => [b.stream, b.error]));\n // Handled-with-error stays a single index now: `block` discriminates\n // the marker (✗ vs ⚠); the failure exists independently of whether\n // ack happened.\n const failed_by_stream = new Map(\n handled.filter((h) => h.error).map((h) => [h.lease.stream, h] as const)\n );\n const detail = leased\n .map(({ stream, at, retry }) => {\n const f = fetch_by_stream.get(stream);\n // Target stream in yellow so the operator's eye lands on \"which\n // stream did this happen on?\" first; source (the events' origin)\n // stays dim — secondary info.\n const key = f?.source\n ? `${hue(C_STREAM, stream)}${dim(`<-${f.source}`)}`\n : hue(C_STREAM, stream);\n const events = f?.events.length\n ? ` ${dim(\n `[${f.events.map(({ id, name }) => `#${id} ${String(name)}`).join(\", \")}]`\n )}`\n : \"\";\n // Build ack + fail segments independently — both can fire for\n // the same stream in the partial-success-then-failure case.\n const acked_at = acked_by_stream.get(stream);\n const ack_part =\n acked_at !== undefined\n ? hue(C_HIT, `✓ @${acked_at}`) // ✓ + new at in lime\n : \"\";\n const failure = failed_by_stream.get(stream);\n let fail_part = \"\";\n if (failure) {\n // Failed event id when known (per-event path), else falls back\n // to lease.at — the post-fetch watermark — for batch-mode\n // total failures where no single event is \"the one.\"\n const failed_at = failure.failed_at ?? at;\n const blocked_error = blocked_by_stream.get(stream);\n if (blocked_error !== undefined) {\n fail_part = `${hue(C_ERR, `✗ @${failed_at}/${retry}`)} ${dim(`(${blocked_error})`)}`;\n } else {\n fail_part = `${hue(C_MISS, `⚠ @${failed_at}/${retry}`)} ${dim(`(${failure.error})`)}`;\n }\n }\n let tail: string;\n if (ack_part && fail_part) tail = ` ${ack_part} ${fail_part}`;\n else if (ack_part) tail = ` ${ack_part}`;\n else if (fail_part) tail = ` ${fail_part}`;\n else tail = ` ${dim(`⊘ @${at}/${retry}`)}`; // nothing happened\n return `${key}${events}${tail}`;\n })\n .join(\", \");\n logger.trace(`${drain_caption(\"drained\", lane)} ${detail}`);\n}\n","/**\n * @module projection-fold\n * @category Internal\n *\n * Fold engine behind `projection(name).of(state)` — maintains per-stream\n * folded states in a bounded in-memory cache and flushes one row per dirty\n * stream per round, so write amplification tracks the distinct-key count\n * instead of the event count.\n *\n * The flush payload deliberately has no type of its own: a state\n * projection flushes the cache layer outward — the rows ARE the\n * streams' {@link CacheEntry} values.\n *\n * Correctness discipline:\n * - The engine runs as the projection's batch handler, so the watermark\n * acks only after a fully-flushed batch — fold work is never\n * acknowledged before it is durable.\n * - On first sight of a stream the engine loads its head state through\n * the same `load()` the command path uses (cache, snapshots and all).\n * The loaded snapshot carries its own head position (`version` and the\n * global event `id`), captured atomically with `state`, so the engine\n * never pairs a stale state with a newer head id read separately from\n * the cache (ACT-1204). Fetched events at or below the loaded id are\n * skipped, later ones fold through the state's own patch reducers.\n * - Eviction under `maxCachedStates` pressure flushes the evictee first\n * (flush-before-evict) — eviction never loses folded work.\n */\nimport type {\n BatchHandler,\n CacheEntry,\n Schema,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport type { FoldConfig } from \"./config.js\";\nimport { bare_patch, load, type PatchFn } from \"./event-sourcing.js\";\nimport { pii_strip } from \"./sensitive.js\";\n\n// The fold config schema, defaults, and resolver live in `./config.js` (the\n// single home for builder-facing config bags). This module keeps the fold\n// engine that consumes the resolved config.\n\n/**\n * A stream's in-flight fold: a mutable {@link CacheEntry} plus the\n * engine's `dirty` flag. Mutable because the hot loop updates one\n * object per stream rather than allocating per event; the required\n * frontier fields are what keep a warm-cache load from ever\n * re-applying history. Stripping `dirty` at the flush boundary yields\n * the entry — the flush payload IS the cache entry.\n */\ntype Fold<TState extends Schema> = {\n -readonly [K in keyof CacheEntry<TState>]: CacheEntry<TState>[K];\n} & { dirty: boolean };\n\n/**\n * Build the batch handler that folds a state's events into per-stream rows.\n * The returned closure is long-lived (one per built projection): its cache\n * survives across drain cycles, so warm streams fold without I/O.\n */\nexport function make_fold_handler<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n>(\n me: State<TState, TEvents, TActions>,\n flush: (rows: ReadonlyArray<CacheEntry<TState>>) => Promise<void>,\n config: FoldConfig,\n patch_fn: PatchFn = bare_patch,\n sensitive_fields: (event_name: string) => readonly string[]\n): BatchHandler<TEvents> {\n // First-sight head loads must apply the SAME PII treatment as the warm\n // path (which folds `pii_strip`ped events handed in by the batch handler):\n // sensitive keys removed entirely, not gated to `[REDACTED]`. `load()`\n // folds over `me.view`, so compose the view with `pii_strip` for sensitive\n // events — otherwise an actorless head load would gate to `[REDACTED]` and\n // the projected row would differ from the warm path by cache warmth (#1320).\n // For a non-PII projection every lookup is empty, so `load_me === me`\n // behaviorally.\n const load_me: State<TState, TEvents, TActions> = {\n ...me,\n view: (raw, actor) => {\n const viewed = me.view(raw, actor);\n const fields = sensitive_fields(viewed.name as string);\n return fields.length\n ? (pii_strip(viewed as never, fields) as typeof viewed)\n : viewed;\n },\n };\n // Insertion-ordered Map as LRU: first key is the oldest. A promote is\n // delete + re-insert. Not the shared LruMap — eviction here must await\n // a flush, and a sync auto-evicting set() would drop folded work.\n const cache = new Map<string, Fold<TState>>();\n\n const row = ({ dirty: _, ...row }: Fold<TState>): CacheEntry<TState> => row;\n\n const flush_dirty = async () => {\n const rows: CacheEntry<TState>[] = [];\n const flushed: Fold<TState>[] = [];\n for (const f of cache.values())\n if (f.dirty) {\n rows.push(row(f));\n flushed.push(f);\n }\n if (rows.length === 0) return;\n await flush(rows);\n for (const f of flushed) f.dirty = false;\n };\n\n return async (events) => {\n let folded_since_flush = 0;\n for (const event of events) {\n const stream = event.stream;\n let fold = cache.get(stream);\n if (fold) {\n // promote to most-recent\n cache.delete(stream);\n cache.set(stream, fold);\n } else {\n if (cache.size >= config.maxCachedStates) {\n // flush-before-evict: the oldest entry leaves only after its\n // folded work is durable.\n const oldest = cache.keys().next().value as string;\n const evictee = cache.get(oldest) as Fold<TState>;\n if (evictee.dirty) await flush([row(evictee)]);\n cache.delete(oldest);\n }\n // First sight of this stream: load its head state through the\n // regular load path (cache, snapshots). The loaded state and its\n // head position (`version`, global `id`, `patches`, `snaps`) are\n // captured atomically inside `load()` — even on a warm cache hit\n // where `snapshot.event` is undefined. Reading the head id back\n // from the cache separately (ACT-1204) opened a TOCTOU window: a\n // concurrent `action()` committing between the two awaits pairs\n // this OLDER state with a NEWER event_id, and the\n // `event.id > fold.event_id` guard below then permanently skips\n // the intervening events. Dirty from the start: the row must be\n // written at least once.\n const snapshot = await load(load_me, { stream }, undefined, patch_fn);\n fold = {\n stream,\n state: snapshot.state,\n version: snapshot.version,\n event_id: snapshot.id,\n patches: snapshot.patches,\n snaps: snapshot.snaps,\n dirty: true,\n };\n cache.set(stream, fold);\n }\n if (event.id > fold.event_id) {\n const reducer = me.patch[event.name as keyof TEvents];\n fold.state = patch_fn(\n me,\n fold.state,\n reducer(event as never, fold.state),\n event as never\n );\n fold.version = event.version;\n fold.event_id = event.id;\n fold.patches++;\n fold.dirty = true;\n } else {\n // Already folded (head load or redelivery) — mark dirty anyway\n // so replays repopulate the read table: this is what keeps a\n // rebuild at one upsert per stream instead of zero.\n fold.dirty = true;\n }\n if (++folded_since_flush >= config.flushEvery) {\n await flush_dirty();\n folded_since_flush = 0;\n }\n }\n // Flush before returning: the drain acks this batch's watermark only\n // after the handler resolves, so rows are durable before the ack.\n await flush_dirty();\n };\n}\n","/**\n * @module reactions\n * @category Internal\n *\n * Reaction dispatch — what runs inside the drain pipeline once `run_drain_cycle`\n * has fetched events for a leased stream. Two shapes:\n *\n * - per-event `handle`: walks payloads sequentially, builds a scoped `IAct`\n * that auto-injects `reactingTo` so handlers don't have to thread it\n * through manually\n * - bulk `handle_batch`: hands every event for a static-target projection to\n * a single batch callback, enabling one-transaction replays\n *\n * Both share `_finalize`, which collapses the retry-vs-block decision and\n * the \"report error only when nothing was handled\" rule.\n *\n * @internal\n */\n\nimport {\n type Actor,\n type BatchHandler,\n type Committed,\n type DoOptions,\n type IAct,\n type Lease,\n type Logger,\n NonRetryableError,\n type ReactionOptions,\n type ReactionPayload,\n type Schemas,\n type Target,\n} from \"../types/index.js\";\nimport { compute_backoff_delay } from \"./backoff.js\";\nimport { CloseSignal } from \"./close-signal.js\";\nimport { resolve_defer_at } from \"./defer-config.js\";\nimport { DeferSignal } from \"./defer-signal.js\";\nimport type { Handle, HandleBatch, HandleResult } from \"./drain-cycle.js\";\n\n/**\n * Dependencies a reaction handler needs from the orchestrator: the logger\n * for retry/error breadcrumbs, plus the bound `IAct` methods that the scoped\n * proxy hands to user reaction code.\n *\n * @internal\n */\nexport type ReactionDeps<\n TEvents extends Schemas,\n TActions extends Schemas,\n TActor extends Actor = Actor,\n> = {\n readonly logger: Logger;\n readonly bound_do: IAct<TEvents, TActions, TActor>[\"do\"];\n readonly bound_load: IAct<TEvents, TActions, TActor>[\"load\"];\n readonly bound_query: IAct<TEvents, TActions, TActor>[\"query\"];\n readonly bound_query_array: IAct<TEvents, TActions, TActor>[\"query_array\"];\n readonly bound_forget: IAct<TEvents, TActions, TActor>[\"forget\"];\n};\n\n/**\n * Shared finalization: log the error and decide retry vs. block. The\n * error string is *always* surfaced on the failure path — drain-cycle\n * uses `handled > 0` (not `error` presence) to decide whether to ack\n * the partial progress, so the message can travel for trace + blocked\n * record without affecting the ack/skip choice.\n */\nfunction finalize(\n lease: Lease,\n handled: number,\n at: number,\n error: Error | undefined,\n options: ReactionOptions,\n logger: Logger,\n failed_at?: number\n): HandleResult {\n if (!error) return { lease, handled, acked_at: at };\n logger.error(error);\n // A `NonRetryableError` from the handler short-circuits the retry\n // budget — block on first attempt when the operator has opted in via\n // `blockOnError`. When `blockOnError` is false, the operator has\n // explicitly chosen \"retry forever,\" so we don't override that.\n const non_retryable = error instanceof NonRetryableError;\n const block =\n options.blockOnError &&\n (non_retryable || lease.retry >= options.maxRetries);\n if (block)\n logger.error(\n non_retryable\n ? `Blocking ${lease.stream} on non-retryable error.`\n : `Blocking ${lease.stream} after ${lease.retry} retries.`\n );\n // Backoff applies only on retry paths — successful handles and terminal\n // blocks never defer. `lease.retry` here is the just-failed attempt's\n // counter, so the delay paces the *next* attempt.\n const next_attempt_at =\n !block && options.backoff\n ? Date.now() + compute_backoff_delay(lease.retry, options.backoff)\n : undefined;\n return {\n lease,\n handled,\n acked_at: at,\n error: error.message,\n block,\n next_attempt_at,\n failed_at,\n };\n}\n\n/**\n * Builds the per-event reaction dispatcher passed to `run_drain_cycle`.\n *\n * The scoped `IAct` proxy auto-injects the triggering event as `reactingTo`\n * when handlers call `do()` without it (#587), keeping the correlation\n * chain by default. The non-do methods are reused across all dispatches —\n * only `do` rebinds per payload because it captures the triggering event.\n *\n * @internal\n */\nexport function build_handle<\n TEvents extends Schemas,\n TActions extends Schemas,\n TActor extends Actor = Actor,\n>(deps: ReactionDeps<TEvents, TActions, TActor>): Handle<TEvents> {\n const {\n logger,\n bound_do,\n bound_load,\n bound_query,\n bound_query_array,\n bound_forget,\n } = deps;\n return async (lease, payloads) => {\n if (payloads.length === 0) return { lease, handled: 0, acked_at: lease.at };\n\n const stream = lease.stream;\n // One event fans out to one payload per matching reaction, and the\n // watermark may only advance past an event once EVERY reaction on it\n // has handled it — acking mid-group would silently drop the remaining\n // reactions on redelivery (#1179). Track the last payload index per\n // event id (payloads arrive in event order) so `at` advances exactly\n // when a group completes; `handled` counts completed events, not\n // payloads, so a mid-group failure with no completed events is a\n // no-progress result (no ack, retry counter advances toward\n // `blockOnError` instead of resetting on every partial pass).\n const last_index_of = new Map<number, number>();\n for (let i = 0; i < payloads.length; i++)\n last_index_of.set(payloads[i].event.id, i);\n let at = lease.at;\n let handled = 0;\n\n if (lease.retry > 0)\n logger.warn(\n `Retrying ${stream}@${payloads.at(0)!.event.id} (${lease.retry}).`\n );\n\n const scoped_app: IAct<TEvents, TActions, TActor> = {\n do: bound_do,\n load: bound_load,\n query: bound_query,\n query_array: bound_query_array,\n forget: bound_forget,\n };\n\n for (let i = 0; i < payloads.length; i++) {\n const payload = payloads[i];\n const { event, handler } = payload;\n scoped_app.do = <TKey extends keyof TActions & string>(\n action: TKey,\n target: Target<TActor>,\n action_payload: Readonly<TActions[TKey]>,\n options?: DoOptions<TEvents>\n ) =>\n bound_do(action, target, action_payload, {\n ...options,\n reactingTo:\n options?.reactingTo ?? (event as Committed<Schemas, string>),\n });\n try {\n await handler(event, stream, scoped_app);\n if (last_index_of.get(event.id) === i) {\n at = event.id;\n handled++;\n }\n } catch (error) {\n // A defer is not a failure: hold the triggering events pending\n // (exclude from ack via `defer`), don't bump `retry`, and re-visit\n // the stream at the carried due-time (#1090). `acked_at` is unused on\n // the defer path — drain never acks a deferred result.\n if (error instanceof DeferSignal)\n return {\n lease,\n handled,\n acked_at: at,\n defer: resolve_defer_at<TEvents>(error.when, event),\n };\n // A close request advances past the triggering event (so the\n // requesting reaction isn't counted as in-flight by the close-cycle\n // guard) and hands the target to the orchestrator's on_close (#1090).\n if (error instanceof CloseSignal)\n return {\n lease,\n handled: handled + 1,\n // Advance to the live head the handler evaluated against (when\n // provided) so the close-cycle guard sees this reaction caught up.\n acked_at: error.at ?? event.id,\n // Close the signalled stream (the autoclose reaction's aggregate,\n // which differs from its synthetic lease stream); a self-closing\n // user reaction omits it and closes its own lease stream. A\n // carried `before` makes it a windowed close (prune, not retire).\n close: {\n stream: error.stream ?? stream,\n archive: error.archive,\n before: error.before,\n },\n };\n return finalize(\n lease,\n handled,\n at,\n error as Error,\n payload.options,\n logger,\n event.id\n );\n }\n }\n return finalize(lease, handled, at, undefined, payloads[0].options, logger);\n };\n}\n\n/**\n * Builds the bulk reaction dispatcher passed to `run_drain_cycle`. All events\n * for a static-target projection are handed to a single callback so the\n * projection can do one transaction per drain (catch-up replays especially).\n *\n * @internal\n */\nexport function build_handle_batch<TEvents extends Schemas>(\n logger: Logger\n): HandleBatch<TEvents> {\n return async (\n lease: Lease,\n payloads: ReactionPayload<TEvents>[],\n batchHandler: BatchHandler<TEvents>\n ) => {\n const stream = lease.stream;\n const events = payloads.map(\n (p) => p.event as Committed<TEvents, keyof TEvents & string>\n );\n const options = payloads[0].options;\n\n if (lease.retry > 0)\n logger.warn(`Retrying batch ${stream}@${events[0].id} (${lease.retry}).`);\n\n try {\n await batchHandler(events, stream);\n return finalize(\n lease,\n events.length,\n events.at(-1)!.id,\n undefined,\n options,\n logger\n );\n } catch (error) {\n return finalize(lease, 0, lease.at, error as Error, options, logger);\n }\n };\n}\n","/**\n * @module settle\n * @category Internal\n *\n * Debounced correlate→drain loop. Sits one level above both correlation\n * and drain: schedule() coalesces rapid callers into a single cycle, then\n * runs correlate+drain in a loop until a pass produces no progress.\n *\n * Owns the debounce timer and the reentrancy flag. Everything else is\n * supplied via the `SettleDeps` callbacks so this module stays free of\n * orchestrator state.\n *\n * @internal\n */\n\nimport type {\n Drain,\n DrainOptions,\n Query,\n Schemas,\n SettleOptions,\n} from \"../types/index.js\";\nimport type { CircuitBreaker } from \"./circuit-breaker.js\";\n\n/**\n * Callbacks the settle loop needs from the orchestrator. Modeled as an\n * input bag so this file doesn't import `Act` (avoids a cycle) and stays\n * independently testable.\n *\n * @internal\n */\nexport type SettleDeps<TEvents extends Schemas> = {\n readonly init: () => Promise<void>;\n readonly checkpoint: () => number;\n readonly correlate: (\n query: Query\n ) => Promise<{ subscribed: number; last_id: number }>;\n readonly drain: (options: DrainOptions) => Promise<Drain<TEvents>>;\n readonly on_settled: (drain: Drain<TEvents>) => void;\n /**\n * Shared orchestrator circuit breaker (ACT-984). The settle loop's\n * `correlate` (subscribe + query) is a store consumer too: a successful\n * pass records `passed()`, a failed one `failed(now, err)` — feeding the\n * same breaker that paces the drain loop, which also surfaces the failure\n * to the `error` lifecycle event.\n */\n readonly breaker: CircuitBreaker;\n /**\n * Whether `correlate` actually probes the store (the app has dynamic\n * resolvers). When false, correlate is a pure no-op early-return that\n * touches no store — so a settle pass has NO store-health signal and must\n * NOT record a breaker `passed()`. Recording a fictitious success there\n * would re-close an OPEN breaker mid-outage on a static-reaction app and\n * let the following drain hammer the down store (#1329). The drain loop's\n * own `passed()`/`failed()` on its real claim keeps the breaker accurate.\n */\n readonly correlate_probes_store: boolean;\n};\n\n/**\n * Drives the debounced correlate→drain catch-up cycle. One instance per\n * Act orchestrator.\n *\n * @internal\n */\nexport class SettleLoop<TEvents extends Schemas> {\n private _timer: ReturnType<typeof setTimeout> | undefined = undefined;\n private _running = false;\n /**\n * Set when a `schedule()` timer fires while a cycle is still running\n * (ACT-1205). The in-flight cycle's `finally` re-arms one more pass so\n * the wake-up isn't dropped — a commit landing during the final\n * no-progress drain pass would otherwise leave armed controllers with\n * nothing to re-drain on an instance with no lane `cycleMs` and no\n * polling. Carries the options of the dropped call so the re-armed\n * pass honors its `debounceMs`/`maxPasses`/drain overrides.\n */\n private _pending: SettleOptions | undefined = undefined;\n private readonly _deps: SettleDeps<TEvents>;\n /** Debounce window applied when the caller doesn't override via `SettleOptions.debounceMs`. */\n private readonly _default_debounce_ms: number;\n\n constructor(deps: SettleDeps<TEvents>, default_debounce_ms: number) {\n this._deps = deps;\n this._default_debounce_ms = default_debounce_ms;\n }\n\n /**\n * Schedule a settle pass. Multiple calls inside the debounce window\n * coalesce into one cycle. The cycle runs correlate→drain in a loop\n * until no progress is made (no new subscriptions, no acks, no blocks)\n * or `maxPasses` is reached, then emits the `\"settled\"` lifecycle event\n * via {@link SettleDeps.on_settled}.\n */\n schedule(options: SettleOptions = {}): void {\n const {\n debounceMs = this._default_debounce_ms,\n correlate: correlate_query = { after: -1, limit: 100 },\n maxPasses = Infinity,\n ...drain_options\n } = options;\n\n if (this._timer) clearTimeout(this._timer);\n this._timer = setTimeout(() => {\n this._timer = undefined;\n // A cycle is already running. Record this wake-up as pending rather\n // than dropping it (ACT-1205) — the running cycle's `finally`\n // re-schedules it so armed controllers always get one more drain.\n if (this._running) {\n this._pending = options;\n return;\n }\n this._running = true;\n\n (async () => {\n await this._deps.init();\n // Accumulated across every pass, so `settled` reports what the\n // SETTLE did rather than what its last pass did. The loop only\n // exits on a pass that made no progress, so emitting that pass\n // alone meant the payload was always empty — while the guide tells\n // operators to sum `drain.fetched` for throughput (#1383).\n let settled_drain: Drain<TEvents> | undefined;\n // Loop correlate→drain until a pass produces no work — this fully\n // catches up paginated streams (e.g. after `reset()` on a long\n // projection) without forcing callers to roll their own loop.\n // `maxPasses` caps runtime in pathological cases.\n for (let i = 0; i < maxPasses; i++) {\n const after_before = this._deps.checkpoint();\n const { subscribed, last_id } = await this._deps.correlate({\n ...correlate_query,\n after: after_before,\n });\n // correlate (subscribe + query) succeeded — the store responded.\n // But only record the success when correlate actually PROBED the\n // store: a static-reaction app's correlate is a no-op early-return\n // that touches nothing, so a `passed()` here would fictitiously\n // re-close an OPEN breaker mid-outage and let the drain below\n // hammer the down store (#1329). drain's own passed()/failed() on\n // its real claim keeps the breaker accurate for those apps.\n if (this._deps.correlate_probes_store) this._deps.breaker.passed();\n const drain = await this._deps.drain(drain_options);\n settled_drain = settled_drain\n ? {\n fetched: [...settled_drain.fetched, ...drain.fetched],\n leased: [...settled_drain.leased, ...drain.leased],\n acked: [...settled_drain.acked, ...drain.acked],\n blocked: [...settled_drain.blocked, ...drain.blocked],\n }\n : drain;\n // `last_id > after_before` counts correlate consuming events as\n // progress even when nothing subscribed or drained this pass — a\n // bounded correlate window (`limit`) full of inert events would\n // otherwise break the loop before a reactive event just past the\n // window is ever scanned. Terminates: ids are monotonic and\n // finite, so once no events remain `last_id === after_before`.\n const made_progress =\n subscribed > 0 ||\n drain.acked.length > 0 ||\n drain.blocked.length > 0 ||\n last_id > after_before;\n if (!made_progress) break;\n }\n // The `.catch` below treats anything it sees as a store failure,\n // because everything else in this block is one. An uncontained\n // listener throw was therefore recorded via `breaker.failed()` —\n // surfacing a spurious `error` event on every settle, and, at\n // `failureThreshold: 1`, opening the breaker so `drain` returned\n // EMPTY_DRAIN for the whole cooldown. Each half-open recovery\n // re-tripped it, so a broken metrics bridge stalled the reaction\n // pipeline indefinitely (#1436). Containment now lives in\n // `Act.emit`, which guards each listener individually (#1437), so\n // no throw escapes `on_settled` to reach that catch.\n if (settled_drain) this._deps.on_settled(settled_drain);\n })()\n .catch((err) => {\n // correlate / init failed (a store op). Record on the shared\n // breaker, which logs it and surfaces the `error` event; the\n // drain loop reads the same breaker to pace itself.\n this._deps.breaker.failed(Date.now(), err);\n })\n .finally(() => {\n this._running = false;\n // A wake-up arrived mid-cycle. Re-arm one more pass with its\n // options so the requested drain actually happens (ACT-1205).\n const pending = this._pending;\n if (pending !== undefined) {\n this._pending = undefined;\n this.schedule(pending);\n }\n });\n }, debounceMs);\n }\n\n /** Cancel any pending or active settle cycle. Idempotent. */\n stop(): void {\n // Drop a mid-cycle wake-up too — a stopped loop must not re-arm from\n // the running cycle's `finally` (ACT-1205).\n this._pending = undefined;\n if (this._timer) {\n clearTimeout(this._timer);\n this._timer = undefined;\n }\n }\n}\n","/**\n * @module act-builder\n * @category Builders\n *\n * Fluent builder for composing event-sourced applications.\n */\nimport { Act, type ActOptions } from \"../act.js\";\nimport {\n bare_patch,\n current_version_of,\n deprecated_event_names,\n type EventGate,\n IDENTITY_GATE,\n make_fold_handler,\n make_gate,\n merge_event_register,\n merge_projection,\n type PatchFn,\n pii_fields,\n pii_split,\n pii_strip,\n reaction_on,\n register_lane,\n register_state,\n resolveActConfig,\n resolveAutocloseConfig,\n resolveLaneConfig,\n synthesize_autoclose_reactions,\n validating_patch,\n} from \"../internal/index.js\";\nimport { DEFAULT_LANE, log } from \"../ports.js\";\nimport type {\n Actor,\n BatchHandler,\n LaneConfig,\n Reaction,\n Registry,\n Schema,\n SchemaRegister,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport type { BuilderBase } from \"./builder-base.js\";\nimport type { Projection } from \"./projection-builder.js\";\nimport type { Slice } from \"./slice-builder.js\";\n\n/**\n * Registers a projection's batch handler against its target stream, throwing\n * if a different handler is already registered for the same target. Two\n * projections silently overwriting each other's batch handlers used to be a\n * latent footgun.\n *\n * This half covers batch x batch only. A fold projection (`.of(...)`) has a\n * target but no batch handler, so it early-returns here — the fold side of\n * the guard lives at the `fold_specs.push` site in `build()`, which sees a\n * fully-populated `batch_handlers` and so catches both orders (#1440).\n */\nfunction register_batch_handler(\n proj: Projection<any>,\n batch_handlers: Map<string, BatchHandler<any>>\n): void {\n if (!proj.batchHandler || !proj.target) return;\n const existing = batch_handlers.get(proj.target);\n if (existing && existing !== proj.batchHandler) {\n throw new Error(\n `Duplicate projection target \"${proj.target}\" — a target is served by one batch handler or one state projection, never both`\n );\n }\n batch_handlers.set(proj.target, proj.batchHandler);\n}\n\n/**\n * Runtime backstop for slice-declared lane references — rejects\n * static `.to({lane})` entries that aren't in the declared set.\n * Inline reactions are caught at compile time; this only fires for\n * slices built against older type definitions.\n */\nfunction validate_lane_references(\n registry: Registry<any, any, any>,\n lanes: ReadonlyArray<LaneConfig>\n): void {\n const declared = new Set<string>([DEFAULT_LANE, ...lanes.map((l) => l.name)]);\n for (const [event_name, def] of Object.entries(registry.events)) {\n const entry = def as { reactions: Map<string, Reaction<any, any>> };\n for (const [handlerName, reaction] of entry.reactions) {\n const resolver = reaction.resolver;\n if (typeof resolver === \"function\") continue;\n const lane = (resolver as { lane?: string }).lane;\n if (lane && !declared.has(lane)) {\n throw new Error(\n `Reaction \"${handlerName}\" on \"${event_name}\" targets undeclared lane \"${lane}\". ` +\n `Declared lanes: ${[...declared].map((l) => `\"${l}\"`).join(\", \")}. ` +\n `Add \\`.withLane({ name: \"${lane}\", ... })\\` to act() or correct the .to() declaration.`\n );\n }\n }\n }\n}\n\n/**\n * Fluent builder interface for composing event-sourced applications.\n *\n * Provides a chainable API for:\n * - Registering states via `.withState()`\n * - Registering slices via `.withSlice()`\n * - Registering projections via `.withProjection()`\n * - Locking a custom actor type via `.withActor<TActor>()`\n * - Declaring drain lanes via `.withLane({name, ...})` (ACT-1103)\n * - Defining event reactions via `.on()` → `.do()` → `.to()`\n * - Building the orchestrator via `.build()`\n *\n * @template TSchemaReg - Schema register for states (maps action names to state schemas)\n * @template TEvents - Event schemas (maps event names to event data schemas)\n * @template TActions - Action schemas (maps action names to action payload schemas)\n * @template TStateMap - Map of state names to state schemas\n * @template TActor - Actor type extending base Actor\n * @template TLanes - Union of declared lane names (ACT-1103). Narrowed by\n * `.withLane({name})` calls so `.to({lane})` and `ActOptions.onlyLanes`\n * reject typos at compile time. Starts at `\"default\"`.\n *\n * @see {@link act} for usage examples\n * @see {@link Act} for the built orchestrator API\n */\nexport interface ActBuilder<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n TLanes extends string = typeof DEFAULT_LANE,\n> extends BuilderBase<\n ActBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor, TLanes>,\n TEvents,\n TActions,\n TActor,\n TLanes\n > {\n /**\n * Registers a state definition with the builder.\n *\n * State names, action names, and event names must be unique across the\n * application (partial states with the same name are merged automatically).\n *\n * @throws {Error} If duplicate action or event names are detected\n */\n withState: <\n TNewState extends Schema,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n TNewName extends string = string,\n >(\n state: State<TNewState, TNewEvents, TNewActions, TNewName>\n ) => ActBuilder<\n TSchemaReg & { [K in keyof TNewActions]: TNewState },\n TEvents & TNewEvents,\n TActions & TNewActions,\n TStateMap & { [K in TNewName]: TNewState },\n TActor,\n TLanes\n >;\n /**\n * Registers a slice with the builder.\n *\n * Merges all the slice's states and reactions into the application.\n * State names, action names, and event names must be unique across the\n * application (partial states with the same name are merged automatically).\n *\n * @throws {Error} If duplicate action or event names are detected\n */\n withSlice: <\n TNewSchemaReg extends SchemaRegister<TNewActions>,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n TNewMap extends Record<string, Schema>,\n TNewLanes extends string,\n >(\n slice: Slice<\n TNewSchemaReg,\n TNewEvents,\n TNewActions,\n TNewMap,\n Actor,\n TNewLanes\n >\n ) => ActBuilder<\n TSchemaReg & TNewSchemaReg,\n TEvents & TNewEvents,\n TActions & TNewActions,\n TStateMap & TNewMap,\n TActor,\n TLanes | TNewLanes\n >;\n /**\n * Locks a custom actor type for this application.\n *\n * This is a pure type-level method — it returns the same builder at\n * runtime but narrows the `TActor` generic so that `app.do()` and\n * reaction dispatchers require the richer actor shape.\n *\n * @template TNewActor - Custom actor type extending base Actor\n * @returns The same builder with `TActor` locked to `TNewActor`\n *\n * @example\n * ```typescript\n * type MyActor = { id: string; name: string; role: string; tenantId: string };\n *\n * const app = act()\n * .withActor<MyActor>()\n * .withState(Counter)\n * .build();\n *\n * // Now app.do() requires MyActor in the target\n * await app.do(\"increment\", {\n * stream: \"counter-1\",\n * actor: { id: \"1\", name: \"Alice\", role: \"admin\", tenantId: \"t1\" }\n * }, { by: 5 });\n * ```\n */\n withActor: <TNewActor extends Actor>() => ActBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TNewActor,\n TLanes\n >;\n /**\n * Declares a drain lane (ACT-1103). Lane name narrows `TLanes` so\n * `.to({lane})` and `ActOptions.onlyLanes` type-check against it.\n *\n * @example\n * ```typescript\n * const app = act()\n * .withState(Counter)\n * .withLane({ name: \"slow\", leaseMillis: 60_000, streamLimit: 5 })\n * .on(\"OrderConfirmed\")\n * .do(deliverWebhook)\n * .to({ target: \"webhooks-out\", lane: \"slow\" })\n * .build();\n * ```\n */\n withLane: <const TConfig extends LaneConfig>(\n config: TConfig\n ) => ActBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TActor,\n TLanes | TConfig[\"name\"]\n >;\n /**\n * Builds and returns the Act orchestrator instance.\n *\n * @param options - Optional runtime overrides (see {@link ActOptions}).\n * `options.onlyLanes` is narrowed to the declared `TLanes` union, so\n * `onlyLanes: [\"typo\"]` is a compile error when the lane wasn't\n * declared via `.withLane(...)`.\n * @returns The Act orchestrator instance\n *\n * @see {@link Act} for available orchestrator methods\n */\n build: (\n options?: ActOptions<TLanes>\n ) => Act<TSchemaReg, TEvents, TActions, TStateMap, TActor>;\n}\n\n/* eslint-disable @typescript-eslint/no-empty-object-type -- {} used as generic defaults */\n\n/**\n * Creates a new Act orchestrator builder for composing event-sourced applications.\n *\n * @example Basic application with single state\n * ```typescript\n * const app = act()\n * .withState(Counter)\n * .build();\n * ```\n *\n * @example Application with custom actor type\n * ```typescript\n * type MyActor = { id: string; name: string; role: string };\n *\n * const app = act()\n * .withActor<MyActor>()\n * .withState(Counter)\n * .build();\n * ```\n *\n * @example Application with slices (vertical slice architecture)\n * ```typescript\n * const CounterSlice = slice()\n * .withState(Counter)\n * .on(\"Incremented\")\n * .do(async (event) => { console.log(\"incremented!\"); })\n * .to(\"counter-target\")\n * .build();\n *\n * const app = act()\n * .withSlice(CounterSlice)\n * .build();\n * ```\n *\n *\n * @see {@link ActBuilder} for available builder methods\n * @see {@link Act} for orchestrator API methods\n * @see {@link state} for defining states\n * @see {@link slice} for defining slices\n */\nexport function act<\n // @ts-expect-error empty schema\n TSchemaReg extends SchemaRegister<TActions> = {},\n TEvents extends Schemas = {},\n TActions extends Schemas = {},\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n>(): ActBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor> {\n // Mutable runtime state — one set of references shared across the entire\n // fluent chain. Each `with*` / `on` call mutates these and returns the\n // same builder cast to the widened generic; type fanout is preserved\n // through the public type signatures, runtime allocation is not.\n const states = new Map<string, State<any, any, any>>();\n // Caches behind registry.sensitive_fields / registry.disclosure_predicate /\n // registry.deprecated_events / registry.autoclose_policy. Populated\n // on the first .build() call.\n const _sf = new Map<string, readonly string[]>();\n // Prebuilt default-deny read gates, one per sensitive event. Non-sensitive\n // events are absent → `query_gate` falls back to the shared IDENTITY_GATE.\n const _qg = new Map<string, EventGate>();\n const _dp = new Map<string, (event: any, actor: Actor) => boolean>();\n const _de = new Map<string, ReadonlySet<string>>();\n const _ac = new Map<\n string,\n (stream: string, head: any, count: number) => boolean\n >();\n const _aa = new Map<string, (stream: string, head: any) => Promise<void>>();\n const EMPTY_DEPRECATED: ReadonlySet<string> = new Set();\n const registry: Registry<TSchemaReg, TEvents, TActions> = {\n actions: {} as Registry<TSchemaReg, TEvents, TActions>[\"actions\"],\n events: {} as Registry<TSchemaReg, TEvents, TActions>[\"events\"],\n sensitive_fields: (event_name) => _sf.get(event_name) ?? [],\n query_gate: (event_name) => _qg.get(event_name) ?? IDENTITY_GATE,\n disclosure_predicate: (state_name) => _dp.get(state_name) ?? null,\n deprecated_events: (state_name) => _de.get(state_name) ?? EMPTY_DEPRECATED,\n autoclose_policy: (state_name) => _ac.get(state_name) ?? null,\n autoclose_archiver: (state_name) => _aa.get(state_name) ?? null,\n };\n const pending_projections: Projection<any>[] = [];\n const fold_projections: Projection<any>[] = [];\n const batch_handlers = new Map<string, BatchHandler<any>>();\n // Validated fold-projection ingredients, resolved once on the first\n // build. The HANDLERS themselves are built per `.build()` — see\n // `make_batch_handlers` — because a fold handler owns a mutable\n // per-stream cache that must never be shared across Acts.\n const fold_specs: {\n target: string;\n merged: any;\n flush: any;\n config: any;\n }[] = [];\n const lanes: LaneConfig[] = [];\n\n // Set on the first `.build()` call. Lets the same builder produce\n // many Acts (multi-tenant / A-B testing patterns) without re-merging\n // projections or re-logging the deprecation advisory.\n let _built = false;\n\n /**\n * Wraps a batch handler so the batch dispatcher stays PII-unaware —\n * sensitive keys are stripped from every event before the handler\n * sees it. `_sf` is read lazily at dispatch time, by when the\n * events pass has populated it.\n */\n const pii_wrap =\n (original: BatchHandler<any>) => async (events: any[], stream: string) => {\n const stripped = events.map((e) => {\n const f = _sf.get(e.name as string);\n return f ? pii_strip(e, f) : e;\n });\n return original(stripped as never, stream);\n };\n\n /**\n * Per-Act batch-handler map. Stateless projection handlers are shared\n * with the builder (they carry no state, and `register_batch_handler`\n * already rejects duplicate targets); state-projection FOLD handlers\n * are constructed fresh for every `.build()`.\n *\n * A fold handler owns a mutable per-stream cache of folded state\n * (`projection-fold.ts`), keyed on stream name alone. Sharing one\n * instance across Acts built from the same builder — the documented\n * multi-tenant pattern, and every `fixture(builder)` test — let one\n * Act's folded rows surface in another Act's sink, and made the\n * frontier guard compare event ids originating in different stores.\n * The cache still spans drain cycles within one Act, so the warm-fold\n * performance property is unchanged.\n *\n * Building here also means each Act's fold handlers observe that\n * build's own `patch_fn` (`validateFoldedState` is a per-build\n * option), instead of freezing the first build's choice.\n */\n const make_batch_handlers = (patch_fn: PatchFn) => {\n const handlers = new Map(batch_handlers);\n for (const spec of fold_specs) {\n handlers.set(\n spec.target,\n pii_wrap(\n make_fold_handler(\n spec.merged,\n spec.flush,\n spec.config,\n patch_fn,\n // Head loads strip sensitive keys like the warm path (#1320).\n (event_name) => _sf.get(event_name) ?? []\n )\n ) as never\n );\n }\n return handlers;\n };\n\n // ACT-403: auto-deprecation enforcement. Groups each state's events\n // by base name + `_v<digits>`; the highest version is current, all\n // lower ones are deprecated. Stashes the deprecation set on the\n // registry (`registry.deprecated_events(state_name)`) so the\n // orchestrator can warn post-commit when an action emits one.\n // Scans static `.emit(\"X\")` markers across every state and throws\n // if any target a deprecated event — the only legitimate use of a\n // deprecated event is on the reduce path. Finally, surfaces a\n // one-line startup advisory so operators can see \"your app has\n // legacy events kept for the read path, here's where they live.\"\n const finalize_deprecations = () => {\n const deprecation_summary: Array<{\n state_name: string;\n deprecated: string;\n current: string;\n }> = [];\n for (const state of states.values()) {\n const event_names = Object.keys(state.events);\n const deprecated = deprecated_event_names(event_names);\n if (deprecated.size === 0) continue;\n _de.set(state.name, deprecated);\n for (const name of deprecated) {\n // `current_version_of` is guaranteed non-undefined here — `name`\n // is in `deprecated`, which by construction means a higher-\n // versioned sibling exists in the same group.\n const current = current_version_of(name, event_names) as string;\n deprecation_summary.push({\n state_name: state.name,\n deprecated: name,\n current,\n });\n }\n for (const [action_name, handler] of Object.entries(state.on)) {\n const static_target = (handler as { _static_emit?: string } | undefined)\n ?._static_emit;\n if (static_target && deprecated.has(static_target)) {\n const current = current_version_of(static_target, event_names);\n throw new Error(\n `Action \"${action_name}\" in state \"${state.name}\" emits deprecated event \"${static_target}\". ` +\n `A newer version exists: \"${current}\". Update the .emit() call ` +\n `to target the current version. The reducer (.patch) for ` +\n `\"${static_target}\" stays as-is — historical events still need it.`\n );\n }\n }\n }\n if (deprecation_summary.length > 0) {\n const list = deprecation_summary\n .map(\n (d) =>\n `\"${d.deprecated}\" (current: \"${d.current}\", state: \"${d.state_name}\")`\n )\n .join(\", \");\n log().info(\n `Act registered ${deprecation_summary.length} deprecated event(s): ${list}. ` +\n `These are legacy versions kept for the read path. Consider truncating ` +\n `closed streams via app.close() when feasible to reduce historical event load. ` +\n `See docs/docs/architecture/event-schema-evolution.md.`\n );\n }\n };\n\n // The `as` chain on `self` is the type fanout: each fluent method\n // mutates state and returns `self` cast to its post-call generic\n // signature. Internal-only — public types stay narrow.\n const builder: ActBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor> =\n {\n withState: (state) => {\n register_state(state, states, registry.actions, registry.events);\n return builder as never;\n },\n withSlice: (input) => {\n for (const s of input.states.values()) {\n register_state(s, states, registry.actions, registry.events);\n }\n merge_event_register(registry.events, input.events);\n pending_projections.push(...input.projections);\n for (const slice_lane of input.lanes) {\n const existing = lanes.find((l) => l.name === slice_lane.name);\n if (!existing) {\n lanes.push(slice_lane);\n continue;\n }\n if (\n existing.leaseMillis !== slice_lane.leaseMillis ||\n existing.streamLimit !== slice_lane.streamLimit ||\n existing.cycleMs !== slice_lane.cycleMs\n ) {\n throw new Error(\n `Lane \"${slice_lane.name}\" was already declared with a different config`\n );\n }\n }\n return builder as never;\n },\n withProjection: (proj) => {\n merge_projection(proj as Projection<any>, registry.events);\n register_batch_handler(proj as Projection<any>, batch_handlers);\n if ((proj as Projection<any>).fold)\n fold_projections.push(proj as Projection<any>);\n return builder;\n },\n withActor: <TNewActor extends Actor>() =>\n builder as unknown as ActBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TNewActor\n >,\n withLane: (config) => {\n // Validate the lane bag at declaration (a bad leaseMillis/streamLimit\n // throws ZodError at build, not on the first cycle).\n register_lane(resolveLaneConfig(config), lanes);\n return builder as never;\n },\n on: <TKey extends keyof TEvents>(event: TKey) =>\n reaction_on(event, registry.events, builder) as never,\n build: (options?: ActOptions) => {\n // Validate the top-level scalar knobs at build (the nested autoclose /\n // circuitBreaker bags are validated by their own resolvers). A bad\n // maxSubscribedStreams / settleDebounceMs throws ZodError here.\n resolveActConfig(options);\n // ACT-1238: select the per-event patch step ONCE here — the\n // single selection site. `bare_patch` (the literal pre-#1238\n // `patch()` merge) when `validateFoldedState` is off, else\n // `validating_patch`. The same selected value feeds BOTH the\n // projection-fold handlers below and `build_es` (via the Act\n // constructor), so the command/load paths and the projection\n // path share one choice and neither branches per event.\n const patch_fn: PatchFn =\n options?.validateFoldedState === true ? validating_patch : bare_patch;\n // One-time finalize: merge pending projections and run the\n // deprecation scan + advisory log exactly once. Calling\n // `.build({scoped: ...})` repeatedly (e.g., per tenant) is\n // supported — see extension-points.md § Scoped ports. Without\n // this guard, `merge_projection` would re-add reactions to the\n // shared registry on every call (accumulating `_p`/`_p_p`\n // dedupe suffixes), and the deprecation advisory would log on\n // every tenant.\n if (!_built) {\n for (const proj of pending_projections) {\n merge_projection(proj, registry.events as Record<string, any>);\n register_batch_handler(proj, batch_handlers);\n if (proj.fold) fold_projections.push(proj);\n }\n // State projections fold the registry-merged FULL state — the\n // builder only recorded intent. Resolve here, where every\n // partial has merged, and refuse silently-partial folds: the\n // projection's register must cover the state's whole register.\n // The `patch_fn` selected once at the top of `build()` feeds the\n // fold handlers, matching the command/load paths (ACT-1238).\n for (const proj of fold_projections) {\n const fold = proj.fold!;\n const merged = states.get(fold.name);\n if (!merged)\n throw new Error(\n `State projection \"${proj.target}\" folds \"${fold.name}\", which is not registered — add it via withState/withSlice before build()`\n );\n const missing = Object.keys(merged.events).filter(\n (event_name) => !(event_name in proj.events)\n );\n if (missing.length > 0)\n throw new Error(\n `State projection \"${proj.target}\" of \"${fold.name}\" is missing events ${missing.join(\", \")} — pass every partial of the state to .of()`\n );\n // A target may be claimed exactly once, by a batch handler OR by\n // a fold — `make_batch_handlers` does an unconditional\n // `handlers.set(spec.target, …)`, so without this the last\n // registration silently won (#1440).\n //\n // `register_batch_handler` cannot catch these: it early-returns\n // on `!proj.batchHandler`, and a fold projection has a target but\n // no batch handler, so the fold path bypassed the guard in both\n // directions. The damage was worse than a dead projection — the\n // fold cold-loads the losing target's streams through the\n // stream-keyed cache, so it received the OTHER projection's\n // aggregates and wrote them into its own read table.\n //\n // With this check all four {batch, fold}² pairings throw;\n // previously only batch × batch did.\n if (\n batch_handlers.has(proj.target!) ||\n fold_specs.some((s) => s.target === proj.target)\n )\n throw new Error(\n `Duplicate projection target \"${proj.target}\" — a target is served by one batch handler or one state projection, never both`\n );\n // Record the validated ingredients only. The handler is\n // constructed per `.build()` (see `make_batch_handlers`) — it\n // owns a mutable per-stream fold cache, so one shared instance\n // would leak folded rows between Acts built from this builder.\n fold_specs.push({\n target: proj.target!,\n merged,\n flush: fold.flush,\n config: fold.config,\n });\n }\n finalize_deprecations();\n validate_lane_references(registry, lanes);\n // Precompute the sensitive-field lookup. Iterates each registered\n // event's Zod schema exactly once at build; later commit/load paths\n // hit the cache in O(1). Events with no sensitive fields don't get\n // Build the sensitive-data wiring in three passes (#855):\n //\n // - events pass: precompute the sensitive-field lookup `_sf` from\n // each event's Zod schema; while we're already walking events,\n // wrap their registered reaction handlers so `build_handle`\n // stays PII-unaware.\n // - states pass: snapshot the disclosure predicates into `_dp`,\n // reject `.snap()` on sensitive-bearing states, and build the\n // per-state step delegates the orchestrator calls (`me.view`,\n // `me.message`, wrapped `me.patch[name]`).\n // - batch_handlers pass: wrap each batch handler so the batch\n // dispatcher stays PII-unaware.\n //\n // The orchestrator calls three step delegates per event:\n // - `me.message(validated)` — produces the commit-bound shape\n // (`{name, data, pii?}`) from a validated emit.\n // - `me.patch[event_name](event, state)` — the reducer that\n // derives the next state from the committed event.\n // - `me.view(event, actor)` — produces the caller-visible form\n // (snapshot.event).\n //\n // For PII-free states (the common case) `view` and `message` are\n // bound to identity in `state-builder.ts` and `patch` is the\n // user-declared reducer; the orchestrator's hot path is identical\n // to the pre-#855 code at runtime. For PII-aware states (≥1\n // `sensitive(...)` event), each delegate is rebound to fold the\n // gate / split / merge into the step itself.\n for (const [event_name, reg] of Object.entries(\n registry.events as Record<\n string,\n {\n schema: import(\"zod\").ZodType;\n reactions: Map<string, { handler: any }>;\n }\n >\n )) {\n const fields = pii_fields(reg.schema);\n if (fields.length === 0) continue;\n _sf.set(event_name, fields);\n // Prebuild the default-deny read gate once, capturing `fields`.\n // The actor-less read surfaces (`query`/`query_array`) resolve it\n // by name; non-sensitive events never reach here, so they fall\n // back to the shared IDENTITY_GATE — zero per-event cost.\n _qg.set(event_name, make_gate(fields, null));\n // Strip PII from the event payload before reactions see it.\n for (const [name, reaction] of reg.reactions) {\n const inner = reaction.handler;\n const wrapped = (event: any, stream: string, app: any) =>\n inner(pii_strip(event, fields), stream, app);\n // Preserve handler.name — build_handle asserts on named functions.\n Object.defineProperty(wrapped, \"name\", { value: inner.name });\n reaction.handler = wrapped;\n reg.reactions.set(name, reaction as never);\n }\n }\n for (const state of states.values()) {\n if (state.disclose) _dp.set(state.name, state.disclose);\n if (state.autoclose) _ac.set(state.name, state.autoclose);\n if (state.archive) _aa.set(state.name, state.archive);\n const fields_by_event = new Map<string, readonly string[]>();\n for (const event_name of Object.keys(state.events)) {\n const fields = _sf.get(event_name);\n if (fields) fields_by_event.set(event_name, fields);\n }\n if (fields_by_event.size === 0) continue; // pure — keep state-builder defaults\n // Snapshots write derived state into `__snapshot__.data`, which\n // `forget_pii` cannot reach. Reject the combination at build so\n // the misconfiguration surfaces in dev/CI, not as a silent leak\n // past the GDPR boundary months later.\n if (state.snap) {\n const offending = [...fields_by_event.keys()];\n throw new Error(\n `State \"${state.name}\" cannot snapshot — events {${offending.join(\", \")}} carry sensitive fields. ` +\n \"Snapshots write derived state into __snapshot__.data, which forget_pii cannot reach. \" +\n \"Remove .snap() or remove sensitive(...) markers.\"\n );\n }\n const disclose = state.disclose ?? null;\n state.pii_aware = true;\n // Prebuild one actor-aware read gate per sensitive event, capturing\n // this state's disclosure predicate — the same `make_gate`\n // primitive the query path uses (predicate-less there). A pii-aware\n // state can still declare non-sensitive events; those aren't in\n // `view_gates`, so `state.view` falls back to the shared\n // IDENTITY_GATE — no per-event field lookup, no `?? []` allocation.\n const view_gates = new Map<string, EventGate>();\n for (const [event_name, fields] of fields_by_event) {\n view_gates.set(event_name, make_gate(fields, disclose));\n }\n state.view = (event, actor) =>\n (view_gates.get(event.name as string) ?? IDENTITY_GATE)(\n event,\n actor\n );\n state.message = (validated) => {\n const fields = fields_by_event.get(validated.name as string);\n return fields ? pii_split(validated, fields) : validated;\n };\n }\n for (const [target, original] of batch_handlers) {\n batch_handlers.set(target, pii_wrap(original) as never);\n }\n // Synthesize the autoclose reactions last, once the registry is\n // fully merged — their dynamic resolvers must be present before\n // the orchestrator classifies the registry. The window/cadence\n // knobs resolve from this first build() call's options; repeat\n // builds (per-tenant scoped Acts) share the registry and the\n // synthesized reaction with it.\n synthesize_autoclose_reactions(\n registry,\n states,\n resolveAutocloseConfig(options ?? {})\n );\n // The registry is complete: freeze the containers so any later\n // registration or orchestrator-side mutation throws instead of\n // silently diverging from what was classified. (Reaction maps\n // remain Map instances — the freeze guards the object shape,\n // convention guards the maps.)\n Object.freeze(registry.actions);\n Object.freeze(registry.events);\n Object.freeze(registry);\n _built = true;\n }\n\n return new Act<TSchemaReg, TEvents, TActions, TStateMap, TActor>(\n registry,\n states,\n make_batch_handlers(patch_fn),\n options,\n lanes,\n patch_fn\n );\n },\n events: registry.events,\n };\n return builder;\n}\n","/**\n * @module projection-builder\n * @category Builders\n *\n * Fluent builder for composing projection handlers — read-model updaters\n * that react to events and update external state (databases, caches, etc.).\n *\n * Projections differ from slices: they don't contain states, don't dispatch\n * actions, and are pure side-effect handlers routed to a named stream.\n */\nimport type { ZodType } from \"zod\";\nimport {\n _this_,\n type FoldConfig,\n resolveFoldConfig,\n} from \"../internal/index.js\";\nimport type {\n BatchHandler,\n CacheEntry,\n Committed,\n EventRegister,\n FoldOptions,\n Reaction,\n ReactionResolver,\n Schema,\n Schemas,\n State,\n} from \"../types/index.js\";\n\n/**\n * A self-contained projection grouping read-model update handlers.\n * Projections are composed into an Act orchestrator via `act().withProjection(projection)`.\n *\n * @template TEvents - Event schemas handled by this projection\n */\nexport type Projection<TEvents extends Schemas> = {\n readonly _tag: \"Projection\";\n readonly events: EventRegister<TEvents>;\n readonly target?: string;\n readonly batchHandler?: BatchHandler<TEvents>;\n /**\n * State-fold spec from `.of()`. The builder only records intent — the\n * orchestrator resolves the REGISTRY-MERGED full state at\n * `act().build()` and synthesizes the batch handler there, so the\n * fold always covers every reducer of the state, including partials\n * merged by slices the projection never saw.\n * @internal\n */\n readonly fold?: {\n readonly name: string;\n readonly flush: (rows: ReadonlyArray<CacheEntry<any>>) => Promise<void>;\n readonly config: FoldConfig;\n };\n};\n\n/**\n * The `.of()` continuation: state projections flush the cache layer\n * outward — the rows ARE the streams' {@link CacheEntry} values, one\n * per dirty stream per flush round. Must be an idempotent upsert keyed\n * on `stream` (guard with `event_id` for order safety when a rebuild\n * races a live worker).\n */\ntype FoldFlush<TState extends Schema, TE extends Schemas> = {\n flush: (\n handler: (rows: ReadonlyArray<CacheEntry<TState>>) => Promise<void>\n ) => {\n build: () => Projection<TE>;\n };\n};\n\n/**\n * `.of()` accepts the partials of ONE state (same name, enforced at the\n * type level via `TName`) purely for typing and event registration —\n * the fold itself always runs on the registry-merged full state,\n * resolved at `act().build()`. Passing every partial is required: the\n * orchestrator validates completeness at build and throws on missing\n * events.\n */\ntype OfSignatures = {\n <\n TS1 extends Schema,\n TE1 extends Schemas,\n TA1 extends Schemas,\n TN extends string,\n >(\n s1: State<TS1, TE1, TA1, TN>,\n options?: FoldOptions\n ): FoldFlush<TS1, TE1>;\n <\n TS1 extends Schema,\n TE1 extends Schemas,\n TA1 extends Schemas,\n TS2 extends Schema,\n TE2 extends Schemas,\n TA2 extends Schemas,\n TN extends string,\n >(\n s1: State<TS1, TE1, TA1, TN>,\n s2: State<TS2, TE2, TA2, TN>,\n options?: FoldOptions\n ): FoldFlush<TS1 & TS2, TE1 & TE2>;\n <\n TS1 extends Schema,\n TE1 extends Schemas,\n TA1 extends Schemas,\n TS2 extends Schema,\n TE2 extends Schemas,\n TA2 extends Schemas,\n TS3 extends Schema,\n TE3 extends Schemas,\n TA3 extends Schemas,\n TN extends string,\n >(\n s1: State<TS1, TE1, TA1, TN>,\n s2: State<TS2, TE2, TA2, TN>,\n s3: State<TS3, TE3, TA3, TN>,\n options?: FoldOptions\n ): FoldFlush<TS1 & TS2 & TS3, TE1 & TE2 & TE3>;\n <\n TS1 extends Schema,\n TE1 extends Schemas,\n TA1 extends Schemas,\n TS2 extends Schema,\n TE2 extends Schemas,\n TA2 extends Schemas,\n TS3 extends Schema,\n TE3 extends Schemas,\n TA3 extends Schemas,\n TS4 extends Schema,\n TE4 extends Schemas,\n TA4 extends Schemas,\n TN extends string,\n >(\n s1: State<TS1, TE1, TA1, TN>,\n s2: State<TS2, TE2, TA2, TN>,\n s3: State<TS3, TE3, TA3, TN>,\n s4: State<TS4, TE4, TA4, TN>,\n options?: FoldOptions\n ): FoldFlush<TS1 & TS2 & TS3 & TS4, TE1 & TE2 & TE3 & TE4>;\n};\n\n/** Helper: a single-key record mapping an event name to its Zod schema. */\ntype EventEntry<TKey extends string = string, TData extends Schema = Schema> = {\n [P in TKey]: ZodType<TData>;\n};\n\n/** Infer the handler-result type after registering one event. */\ntype DoResult<\n TEvents extends Schemas,\n TKey extends string,\n TData extends Schema,\n TTarget extends string | undefined = undefined,\n> = ProjectionBuilder<TEvents & { [P in TKey]: TData }, TTarget, true> & {\n to: (\n resolver: ReactionResolver<TEvents & { [P in TKey]: TData }, TKey> | string\n ) => ProjectionBuilder<TEvents & { [P in TKey]: TData }, TTarget, true>;\n};\n\n/**\n * Fluent builder interface for composing projections.\n *\n * When a static target is provided via `projection(\"target\")`, the builder\n * exposes a `.batch()` method for registering a batch handler that processes\n * all events in a single call.\n *\n * @template TEvents - Event schemas\n * @template TTarget - Static target string or undefined\n */\nexport type ProjectionBuilder<\n TEvents extends Schemas,\n TTarget extends string | undefined = undefined,\n THasHandlers extends boolean = false,\n> = {\n /**\n * Begins defining a projection handler for a specific event.\n *\n * Pass a `{ EventName: schema }` record — use shorthand `{ EventName }`\n * when the variable name matches the event name. The key becomes the\n * event name, the value the Zod schema.\n */\n on: <TKey extends string, TData extends Schema>(\n entry: EventEntry<TKey, TData>\n ) => {\n do: (\n handler: (\n event: Committed<TEvents & { [P in TKey]: TData }, TKey>,\n stream: string\n ) => Promise<void>\n ) => DoResult<TEvents, TKey, TData, TTarget>;\n };\n /**\n * Builds and returns the Projection data structure.\n */\n build: () => Projection<TEvents>;\n /**\n * The registered event schemas and their reaction maps.\n */\n readonly events: EventRegister<TEvents>;\n} & (TTarget extends string\n ? {\n /**\n * Registers a batch handler that processes all events in a single call.\n *\n * Only available on projections with a static target (`projection(\"target\")`).\n * The handler receives a discriminated union of all declared events,\n * enabling bulk DB operations in a single transaction.\n *\n * When defined, the batch handler is always called — even for a single event.\n * Individual `.do()` handlers serve as fallback for projections without `.batch()`.\n */\n batch: (handler: BatchHandler<TEvents>) => {\n build: () => Projection<TEvents>;\n };\n } & (THasHandlers extends false\n ? {\n /**\n * Declares a state projection: fold every event of the given\n * state through its own reducers and flush one row per stream —\n * the queryable list of the aggregates themselves.\n *\n * The state is the filter: the projection consumes exactly the\n * state's event register, so in a multi-state app only that\n * state's streams are folded — and every event of a folded\n * stream reaches the reducer. Write amplification tracks the\n * distinct stream count, not the event count; `app.reset`\n * rebuilds in O(streams) upserts.\n *\n * The fluent chain enforces the shape: `.of()` is only offered\n * before any `.on()` handler, and narrows to `.flush()` +\n * `.build()` — a projection either folds a state or declares\n * handlers, never both.\n */\n of: OfSignatures;\n }\n : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {})\n : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {});\n\n/* eslint-disable @typescript-eslint/no-empty-object-type -- {} used as generic defaults */\n\n/**\n * Creates a new projection builder for composing read-model update handlers.\n *\n * Projections enable separation of read-model concerns from command handling.\n * Each `.on({ Event }).do(handler)` call registers a handler that updates\n * a projection (database table, cache, etc.) in response to events.\n *\n * Pass a target stream name to `projection(\"target\")` so every handler\n * inherits that resolver automatically. Omit it and use per-handler\n * `.to()` when handlers route to different streams.\n *\n * @param target - Optional default target stream for all handlers\n *\n * @example Default target (all handlers routed to \"tickets\")\n * ```typescript\n * const TicketProjection = projection(\"tickets\")\n * .on({ TicketOpened })\n * .do(async ({ stream, data }) => {\n * await db.insert(tickets).values({ id: stream, ...data });\n * })\n * .on({ TicketClosed })\n * .do(async ({ stream, data }) => {\n * await db.update(tickets).set(data).where(eq(tickets.id, stream));\n * })\n * .build();\n * ```\n *\n * @example Per-handler routing\n * ```typescript\n * const MultiProjection = projection()\n * .on({ OrderPlaced })\n * .do(async (event) => { ... })\n * .to(\"orders\")\n * .on({ PaymentReceived })\n * .do(async (event) => { ... })\n * .to(\"payments\")\n * .build();\n * ```\n *\n * @see {@link ProjectionBuilder} for builder methods\n * @see {@link Projection} for the output type\n */\n/**\n * @internal Build the core builder object (shared between overloads). One\n * mutable `events` register threaded through every fluent call; .on()\n * mutates and returns the same builder cast to its widened generic.\n */\nfunction _projection<\n TEvents extends Schemas,\n TTarget extends string | undefined,\n>(target: TTarget): ProjectionBuilder<TEvents, TTarget> {\n const events = {} as EventRegister<TEvents>;\n const default_resolver: { target: string } | undefined =\n typeof target === \"string\" ? { target } : undefined;\n\n // Mutable runtime bag — typed loosely; the public projection() return\n // type narrows back to the user-facing `ProjectionBuilder<TEvents, TTarget>`.\n\n const base: any = {\n on: <TKey extends string, TData extends Schema>(\n entry: EventEntry<TKey, TData>\n ) => {\n const keys = Object.keys(entry);\n if (keys.length !== 1) throw new Error(\".on() requires exactly one key\");\n const event = keys[0] as TKey;\n const schema = entry[event];\n\n // Register the event schema if not already present\n if (!(event in events)) {\n (events as Record<string, unknown>)[event] = {\n schema,\n reactions: new Map(),\n };\n }\n\n return {\n do: (\n handler: (\n event: Committed<TEvents & { [P in TKey]: TData }, TKey>,\n stream: string\n ) => Promise<void>\n ) => {\n const reaction: Reaction<TEvents & { [P in TKey]: TData }, TKey> = {\n handler,\n resolver: default_resolver ?? _this_,\n options: {\n blockOnError: true,\n maxRetries: 3,\n },\n };\n const register = (events as Record<string, any>)[event];\n if (!handler.name)\n throw new Error(\n `Projection handler for \"${event}\" must be a named function`\n );\n if (register.reactions.has(handler.name))\n throw new Error(\n `Duplicate projection handler \"${handler.name}\" for event \"${event}\". ` +\n `Projection handlers are keyed by function name; rename one of them.`\n );\n register.reactions.set(handler.name, reaction);\n\n // Same builder, widened generic — no recursive call.\n const widened = base as unknown as ProjectionBuilder<\n TEvents & { [P in TKey]: TData },\n TTarget\n >;\n return Object.assign(widened, {\n to(\n resolver:\n | ReactionResolver<TEvents & { [P in TKey]: TData }, TKey>\n | string\n ) {\n // Patch the same reaction in place — no second Map.set().\n reaction.resolver =\n typeof resolver === \"string\" ? { target: resolver } : resolver;\n return widened;\n },\n });\n },\n };\n },\n build: () => ({\n _tag: \"Projection\" as const,\n events,\n ...(target !== undefined && { target }),\n }),\n events,\n };\n\n // Add .batch() and .of() only for static-target projections\n if (typeof target === \"string\") {\n return Object.assign(base, {\n batch: (handler: BatchHandler<TEvents>) => ({\n build: () => ({\n _tag: \"Projection\" as const,\n events,\n target,\n batchHandler: handler,\n }),\n }),\n of: (...args: unknown[]) => {\n if (Object.keys(events).length > 0)\n throw new Error(\n `Projection \"${target}\" mixes .of() with .on() handlers — a projection either folds a state or declares handlers, never both`\n );\n // Trailing options bag is the only non-State argument.\n const is_state = (a: unknown): a is State<Schema, Schemas, Schemas> =>\n !!a &&\n typeof (a as State<Schema, Schemas, Schemas>).init === \"function\";\n const partials = args.filter(is_state);\n const options = (args.find((a) => !is_state(a)) ?? {}) as FoldOptions;\n if (partials.length === 0)\n throw new Error(`Projection \"${target}\" .of() requires a state`);\n const name = partials[0].name;\n for (const partial of partials)\n if (partial.name !== name)\n throw new Error(\n `Projection \"${target}\" .of() partials must share one state name — got \"${name}\" and \"${partial.name}\"`\n );\n // Misconfiguration surfaces here, at startup — not on first drain.\n const config = resolveFoldConfig(options);\n // The partials' own schema instances register the events, so the\n // same-name declarations in slices pass the identity check in\n // merge_event_register. The named no-op reaction routes fetches\n // to this target; dispatch always goes through the batch handler\n // the orchestrator synthesizes from the registry-merged state.\n const fold_events = {} as EventRegister<Schemas>;\n for (const partial of partials)\n for (const [event_name, schema] of Object.entries(partial.events)) {\n if (event_name in fold_events) continue;\n const noop = {\n [`${target}_fold`]: async () => {},\n }[`${target}_fold`] as (\n event: Committed<Schemas, string>,\n stream: string\n ) => Promise<void>;\n (fold_events as Record<string, unknown>)[event_name] = {\n schema,\n reactions: new Map([\n [\n `${target}_fold`,\n {\n handler: noop,\n resolver: { target },\n options: { blockOnError: true, maxRetries: 3 },\n },\n ],\n ]),\n };\n }\n return {\n flush: (\n handler: (rows: ReadonlyArray<CacheEntry<Schema>>) => Promise<void>\n ) => ({\n build: () => ({\n _tag: \"Projection\" as const,\n events: fold_events,\n target,\n fold: { name, flush: handler, config },\n }),\n }),\n };\n },\n }) as ProjectionBuilder<TEvents, TTarget>;\n }\n\n return base as ProjectionBuilder<TEvents, TTarget>;\n}\n\n/**\n * Creates a new projection builder with a static target stream.\n *\n * All handlers inherit the target resolver automatically. Enables `.batch()`\n * for bulk event processing in a single transaction.\n *\n * @param target - Static target stream for all handlers\n */\nexport function projection<TEvents extends Schemas = {}>(\n target: string\n): ProjectionBuilder<TEvents, string>;\n/**\n * Creates a new projection builder without a default target.\n *\n * Use per-handler `.to()` to route events to different streams.\n */\nexport function projection<TEvents extends Schemas = {}>(\n target?: undefined\n): ProjectionBuilder<TEvents, undefined>;\nexport function projection<TEvents extends Schemas = {}>(\n target?: string\n): ProjectionBuilder<TEvents, string | undefined> {\n return _projection<TEvents, string | undefined>(target);\n}\n","/**\n * @module slice-builder\n * @category Builders\n *\n * Fluent builder for composing partial states with scoped reactions into\n * self-contained functional slices (vertical slice architecture).\n */\nimport {\n reaction_on,\n register_lane,\n register_state,\n} from \"../internal/index.js\";\nimport type { DEFAULT_LANE } from \"../ports.js\";\nimport type {\n Actor,\n EventRegister,\n LaneConfig,\n Schema,\n SchemaRegister,\n Schemas,\n State,\n} from \"../types/index.js\";\nimport type { BuilderBase } from \"./builder-base.js\";\nimport type { Projection } from \"./projection-builder.js\";\n\n/**\n * A self-contained functional slice grouping partial states with their\n * scoped reactions. Slices are composed into an Act orchestrator via\n * `act().withSlice(slice)`.\n *\n * @template TSchemaReg - Schema register for states\n * @template TEvents - Event schemas from this slice's states\n * @template TActions - Action schemas from this slice's states\n * @template TStateMap - Map of state names to state schemas\n * @template TActor - Actor type extending base Actor\n */\nexport type Slice<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n TLanes extends string = typeof DEFAULT_LANE,\n> = {\n readonly _tag: \"Slice\";\n readonly states: Map<string, State<any, any, any>>;\n readonly events: EventRegister<TEvents>;\n readonly projections: ReadonlyArray<Projection<any>>;\n /**\n * Drain lanes declared on this slice via `.withLane(...)` (ACT-1103).\n * `act().withSlice(slice)` merges these into the Act's lane set so\n * `.to({lane})` is statically checked at the slice's call site against\n * the lanes the slice itself declared.\n */\n readonly lanes: ReadonlyArray<LaneConfig>;\n /** @internal phantom field for type-level state schema tracking */\n readonly _S?: TSchemaReg;\n /** @internal phantom field for type-level state name tracking */\n readonly _M?: TStateMap;\n /** @internal phantom field for type-level actor tracking */\n readonly _TActor?: TActor;\n /** @internal phantom field for type-level lane union tracking */\n readonly _TLanes?: TLanes;\n};\n\n/**\n * Fluent builder interface for composing functional slices.\n *\n * Provides a chainable API for registering states and projections,\n * and defining reactions scoped to the slice's own events.\n *\n * @template TSchemaReg - Schema register for states\n * @template TEvents - Event schemas\n * @template TActions - Action schemas\n * @template TStateMap - Map of state names to state schemas\n * @template TActor - Actor type extending base Actor\n */\nexport interface SliceBuilder<\n TSchemaReg extends SchemaRegister<TActions>,\n TEvents extends Schemas,\n TActions extends Schemas,\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n TLanes extends string = typeof DEFAULT_LANE,\n> extends BuilderBase<\n SliceBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor, TLanes>,\n TEvents,\n TActions,\n TActor,\n TLanes\n > {\n /**\n * Registers a state definition with the slice.\n *\n * Include every state whose actions your reaction handlers need to\n * dispatch. Duplicate registrations (same state in multiple slices)\n * are handled automatically at composition time.\n */\n withState: <\n TNewState extends Schema,\n TNewEvents extends Schemas,\n TNewActions extends Schemas,\n TNewName extends string = string,\n >(\n state: State<TNewState, TNewEvents, TNewActions, TNewName>\n ) => SliceBuilder<\n TSchemaReg & { [K in keyof TNewActions]: TNewState },\n TEvents & TNewEvents,\n TActions & TNewActions,\n TStateMap & { [K in TNewName]: TNewState },\n TActor,\n TLanes\n >;\n /**\n * Declares a drain lane on this slice (ACT-1103). Merged into the\n * parent Act's lane set by `act().withSlice(slice)`.\n */\n withLane: <const TConfig extends LaneConfig>(\n config: TConfig\n ) => SliceBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TActor,\n TLanes | TConfig[\"name\"]\n >;\n /**\n * Builds and returns the Slice data structure.\n */\n build: () => Slice<TSchemaReg, TEvents, TActions, TStateMap, TActor, TLanes>;\n}\n\n/* eslint-disable @typescript-eslint/no-empty-object-type -- {} used as generic defaults */\n\n/**\n * Creates a new slice builder for composing partial states with scoped reactions.\n *\n * Slices enable vertical slice architecture by grouping related states and\n * reactions into self-contained feature modules. Reactions defined in a slice\n * are type-scoped to events from that slice's states only.\n *\n * @example Single-state slice with typed dispatch\n * ```typescript\n * const CounterSlice = slice()\n * .withState(Counter)\n * .on(\"Incremented\")\n * .do(async (event, _stream, app) => {\n * await app.do(\"reset\", target, {});\n * })\n * .to(\"counter-target\")\n * .build();\n * ```\n *\n * @example Cross-state dispatch (include both states)\n * ```typescript\n * const CreationSlice = slice()\n * .withState(TicketCreation)\n * .withState(TicketOperations) // handler can dispatch AssignTicket\n * .on(\"TicketOpened\").do(async (event, _stream, app) => {\n * await app.do(\"AssignTicket\", target, payload, { reactingTo: event });\n * })\n * .build();\n * ```\n *\n * @see {@link SliceBuilder} for builder methods\n * @see {@link Slice} for the output type\n */\nexport function slice<\n // @ts-expect-error empty schema\n TSchemaReg extends SchemaRegister<TActions> = {},\n TEvents extends Schemas = {},\n TActions extends Schemas = {},\n TStateMap extends Record<string, Schema> = {},\n TActor extends Actor = Actor,\n>(): SliceBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor> {\n // One mutable state shared across the entire fluent chain. Each\n // `withState` / `withProjection` / `on` call mutates these and returns\n // the same builder cast to the widened generic; type fanout is preserved\n // through the public type signatures, runtime allocation is not.\n const states = new Map<string, State<any, any, any>>();\n const actions: Record<string, any> = {};\n const events = {} as EventRegister<TEvents>;\n const projections: Projection<any>[] = [];\n const lanes: LaneConfig[] = [];\n\n const builder: SliceBuilder<\n TSchemaReg,\n TEvents,\n TActions,\n TStateMap,\n TActor\n > = {\n withState: (state) => {\n register_state(state, states, actions, events as Record<string, unknown>);\n return builder as never;\n },\n withProjection: (proj) => {\n projections.push(proj as Projection<any>);\n return builder;\n },\n withLane: (config) => {\n register_lane(config, lanes);\n return builder as never;\n },\n on: <TKey extends keyof TEvents>(event: TKey) =>\n reaction_on(event, events, builder) as never,\n build: () => ({\n _tag: \"Slice\" as const,\n states,\n events,\n projections,\n lanes,\n }),\n events,\n };\n return builder;\n}\n","/**\n * @module state-builder\n * @category Builders\n *\n * Fluent interface for defining a strongly-typed state machine using Zod schemas.\n */\nimport type { ZodType } from \"zod\";\nimport {\n type AutoclosePolicy,\n compile_autoclose_policy,\n policy_keep_days,\n policy_min_after_days,\n resolveActionConfig,\n} from \"../internal/index.js\";\nimport type {\n ActionHandler,\n ActionOptions,\n Actor,\n AutocloseArchiver,\n AutoclosePredicate,\n Committed,\n GivenHandlers,\n Invariant,\n PassthroughPatchHandler,\n PatchHandlers,\n Schema,\n Schemas,\n Snapshot,\n State,\n ZodTypes,\n} from \"../types/index.js\";\n\n/**\n * Builder interface for defining a state with event sourcing.\n *\n * Provides a fluent API to configure the initial state, event types,\n * and event handlers (reducers) before moving to action configuration.\n *\n * @template TState - State schema type\n * @template TName - State name literal type\n *\n * @see {@link state} for usage examples\n * @see {@link ActionBuilder} for action configuration\n */\nexport type StateBuilder<\n TState extends Schema,\n TName extends string = string,\n> = {\n /**\n * Defines the initial state for new state instances.\n *\n * The init function is called when a new stream is created (first event).\n * It can accept initial data or return a default state.\n *\n * @param init - Function returning the initial state\n * @returns A builder with `.emits()` to declare event types\n *\n * @example\n * ```typescript\n * .init(() => ({ count: 0, created: new Date() }))\n * ```\n *\n * @example With initial data\n * ```typescript\n * .init((data) => ({ ...data, createdAt: new Date() }))\n * ```\n */\n init: (init: () => Readonly<TState>) => {\n /**\n * Declares the event types that this state can emit.\n *\n * Events represent facts that have happened - they should be named in past tense.\n * Each event is defined with a Zod schema for type safety and runtime validation.\n *\n * @template TEvents - Event schemas type\n * @param events - Object mapping event names to Zod schemas\n * @returns An ActionBuilder (with optional `.patch()` to override specific reducers)\n *\n * @example\n * ```typescript\n * .emits({\n * Incremented: z.object({ amount: z.number() }),\n * Decremented: z.object({ amount: z.number() }),\n * Reset: z.object({})\n * })\n * ```\n */\n emits: <TEvents extends Schemas>(\n events: ZodTypes<TEvents>\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- {} avoids string index signature that Record<string, never> would add, keeping keyof A precise\n ) => ActionBuilder<TState, TEvents, {}, TName> & {\n /**\n * Overrides specific event reducers. Events without a custom patch\n * default to passthrough: `({ data }) => data` (event data merges\n * into state).\n *\n * @param patch - Partial map of event names to patch handler functions\n * @returns An ActionBuilder for defining actions\n *\n * @example Only override the events that need custom logic\n * ```typescript\n * .emits({ TicketOpened, TicketClosed, TicketResolved })\n * .patch({\n * TicketOpened: ({ data }) => {\n * const { message, messageId, userId, ...other } = data;\n * return { ...other, userId, messages: { [messageId]: { ... } } };\n * },\n * })\n * // TicketClosed and TicketResolved use passthrough\n * ```\n */\n patch: (\n patch: Partial<PatchHandlers<TState, TEvents>>\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- {} avoids string index signature that Record<string, never> would add, keeping keyof A precise\n ) => ActionBuilder<TState, TEvents, {}, TName>;\n };\n };\n};\n\n/** Helper: a single-key record mapping a state name to its Zod schema. */\ntype StateEntry<\n TKey extends string = string,\n TState extends Schema = Schema,\n> = {\n [P in TKey]: ZodType<TState>;\n};\n\n/** Helper: a single-key record mapping an action name to its Zod schema. */\ntype ActionEntry<\n TKey extends string = string,\n TNewActions extends Schema = Schema,\n> = {\n [P in TKey]: ZodType<TNewActions>;\n};\n\n/**\n * Builder interface for defining actions (commands) on a state.\n *\n * Actions represent user/system intents to modify state. Each action is validated\n * against a schema, can have business rule invariants, and must emit one or more events.\n *\n * @template TState - State schema type\n * @template TEvents - Event schemas type\n * @template TActions - Action schemas type\n * @template TName - State name literal type\n * @template TSnap - `true` once `.snap(...)` has been called. Gates the\n * `.autocloses({ keep })` rolling-window option — a windowed close is\n * meaningless without snapshots, so `keep` only typechecks after\n * `.snap` in the chain.\n *\n * @see {@link state} for complete usage examples\n */\nexport type ActionBuilder<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TName extends string = string,\n TSnap extends boolean = false,\n> = {\n /**\n * Defines an action (command) that can be executed on this state.\n *\n * Actions represent intents to change state - they should be named in imperative form\n * (e.g., \"CreateUser\", \"IncrementCounter\", \"PlaceOrder\"). Actions are validated against\n * their schema and must emit at least one event.\n *\n * Pass a `{ ActionName: schema }` record — use shorthand `{ ActionName }`\n * when the variable name matches the action name. The key becomes the\n * action name, the value the Zod schema.\n *\n * Pass an optional second argument to declare a per-action retry\n * policy — the orchestrator retries this action on\n * {@link ConcurrencyError} up to `maxRetries` extra times, applying\n * `backoff` between attempts when set. Omit the argument to keep the\n * current single-attempt behavior (`ConcurrencyError` surfaces on\n * first conflict).\n *\n * @template TKey - Action name (string literal type)\n * @template TNewActions - Action payload schema type\n * @param entry - Single-key record `{ ActionName: schema }`\n * @param options - Optional per-action retry policy\n * ({@link ActionOptions}).\n * @returns An object with `.given()` and `.emit()` for further configuration\n *\n * @example Simple action without invariants\n * ```typescript\n * .on({ increment: z.object({ by: z.number() }) })\n * .emit((action) => [\"Incremented\", { amount: action.by }])\n * ```\n *\n * @example Hot-stream action with retry + jittered exponential backoff\n * ```typescript\n * .on(\n * { transfer: z.object({ amount: z.number() }) },\n * {\n * maxRetries: 5,\n * backoff: { strategy: \"exponential\", baseMs: 10, maxMs: 200, jitter: true },\n * }\n * )\n * .emit((action) => [\"Transferred\", { amount: action.amount }])\n * ```\n *\n * @example Action with business rules\n * ```typescript\n * .on({ withdraw: z.object({ amount: z.number() }) })\n * .given([\n * { description: \"Account must be open\", valid: (state) => state.status === \"open\" },\n * { description: \"Funds must be available\", valid: (state) => state.balance > 0 }\n * ])\n * .emit((action) => [\"Withdrawn\", { amount: action.amount }])\n * ```\n *\n * @example Action with shorthand (variable name matches action name)\n * ```typescript\n * const OpenTicket = z.object({ title: z.string() });\n * .on({ OpenTicket })\n * .emit((action) => [\"TicketOpened\", { title: action.title }])\n * ```\n */\n on: <TKey extends string, TNewActions extends Schema>(\n entry: ActionEntry<TKey, TNewActions>,\n options?: ActionOptions\n ) => {\n /**\n * Adds business rule invariants that must hold before the action can execute.\n *\n * Invariants are checked after loading the current state but before emitting\n * events. Each invariant pairs a `description` with a `valid(state, actor?)`\n * predicate — when a predicate returns `false`, the action throws\n * `InvariantError` carrying the description. All invariants must pass for\n * the action to succeed.\n *\n * @param rules - Array of {@link Invariant} objects (`{ description, valid }`)\n * @returns An object with `.emit()` to finalize the action\n *\n * @example\n * ```typescript\n * .given([\n * { description: \"Must be active\", valid: (state) => state.status === \"active\" },\n * { description: \"Must be the owner\", valid: (state, actor) => state.ownerId === actor?.id }\n * ])\n * ```\n */\n given: (rules: Invariant<TState>[]) => {\n /**\n * Defines the action handler that emits events.\n *\n * The handler receives the action payload and current state snapshot,\n * and must return one or more events to emit. Events are applied to state\n * via the patch handlers defined earlier.\n *\n * Pass a string event name for passthrough: the action payload becomes\n * the event data directly.\n *\n * @param handler - Function that returns events to emit, or event name string for passthrough\n * @returns The ActionBuilder for chaining more actions\n *\n * @example Custom handler\n * ```typescript\n * .emit((action, snapshot) => {\n * const newBalance = snapshot.state.balance + action.amount;\n * return [\"Deposited\", { amount: action.amount, newBalance }];\n * })\n * ```\n *\n * @example Passthrough (action payload = event data)\n * ```typescript\n * .emit(\"TicketAssigned\")\n * ```\n */\n emit: {\n /** Custom handler — receives `(action, snapshot)` and returns one\n * or more `[EventName, data]` tuples (or `undefined`). */\n (\n handler: ActionHandler<\n TState,\n TEvents,\n { [P in TKey]: TNewActions },\n TKey\n >\n ): ActionBuilder<\n TState,\n TEvents,\n TActions & { [P in TKey]: TNewActions },\n TName,\n TSnap\n >;\n /** Passthrough — the action payload becomes the event data\n * directly. Must reference an event declared in `.emits()`. */\n (\n event_name: keyof TEvents & string\n ): ActionBuilder<\n TState,\n TEvents,\n TActions & { [P in TKey]: TNewActions },\n TName,\n TSnap\n >;\n };\n };\n /**\n * Defines the action handler that emits events. Same two overloads as\n * the post-`.given()` form above:\n *\n * - **Function** — receives `(action, snapshot)` and returns one or\n * more `[EventName, data]` tuples (or `undefined`).\n * - **String** — passthrough: the action payload becomes the event\n * data directly. Must reference an event declared in `.emits()`.\n *\n * The two overloads are kept separate (rather than merged into a\n * `handler | string` union) so that TS contextual typing of the\n * function alternative isn't degraded by considering the string\n * branch — under the union form `TState` could collapse to its\n * `Schema` constraint inside the callback.\n *\n * @example Passthrough (action payload = event data)\n * ```typescript\n * .emit(\"Incremented\")\n * ```\n *\n * @example Single event\n * ```typescript\n * .emit((action) => [\"Incremented\", { amount: action.by }])\n * ```\n *\n * @example Multiple events\n * ```typescript\n * .emit((action) => [\n * [\"Incremented\", { amount: action.by }],\n * [\"LogUpdated\", { message: `Incremented by ${action.by}` }]\n * ])\n * ```\n */\n emit: {\n (\n handler: ActionHandler<\n TState,\n TEvents,\n { [P in TKey]: TNewActions },\n TKey\n >\n ): ActionBuilder<\n TState,\n TEvents,\n TActions & { [P in TKey]: TNewActions },\n TName,\n TSnap\n >;\n (\n event_name: keyof TEvents & string\n ): ActionBuilder<\n TState,\n TEvents,\n TActions & { [P in TKey]: TNewActions },\n TName,\n TSnap\n >;\n };\n };\n /**\n * Defines a snapshotting strategy to optimize state reconstruction.\n *\n * Snapshots store the current state at a point in time, allowing faster state loading\n * by avoiding replaying all events from the beginning. The snap function is called\n * after each event is applied and should return `true` when a snapshot should be taken.\n *\n * @param snap - Predicate function that returns true when a snapshot should be taken\n * @returns The ActionBuilder for chaining\n *\n * @example Snapshot every 10 events\n * ```typescript\n * .snap((snapshot) => snapshot.patches >= 10)\n * ```\n *\n * @example Snapshot based on state size\n * ```typescript\n * .snap((snapshot) => {\n * const estimatedSize = JSON.stringify(snapshot.state).length;\n * return estimatedSize > 10000 || snapshot.patches >= 50;\n * })\n * ```\n *\n * @example Time-based snapshotting\n * ```typescript\n * .snap((snapshot) => {\n * const hoursSinceLastSnapshot = snapshot.patches * 0.1; // Estimate\n * return hoursSinceLastSnapshot >= 24;\n * })\n * ```\n */\n snap: (\n snap: (snapshot: Snapshot<TState, TEvents>) => boolean\n ) => ActionBuilder<TState, TEvents, TActions, TName, true>;\n /**\n * Declares the disclosure predicate for `sensitive(...)`-marked event\n * fields. Gates external reads: returning `true` allows the actor to see\n * plaintext on the event; returning `false` substitutes `\"[REDACTED]\"`.\n * When absent, the framework default-denies on every external read —\n * fail-safe.\n *\n * One predicate per state. A second `.discloses(...)` call replaces the\n * first (same shape as snapshots being state-level, not per-event).\n *\n * The predicate receives the full event including merged PII so it can\n * branch on the payload itself (e.g.\n * `event.data.ownerId === actor.id`). Reducers, projections, and\n * reactions are unaffected — they follow separate visibility rules\n * documented in #855.\n *\n * @param disclose - Predicate `(event, actor) => boolean`. `true` =\n * plaintext, `false` = `\"[REDACTED]\"` substitution.\n * @returns The ActionBuilder for chaining.\n *\n * @example Owner-or-admin disclosure\n * ```typescript\n * state({ User: userSchema })\n * .init(() => ({ ... }))\n * .emits({ UserRegistered: z.object({ email: sensitive(z.string()) }) })\n * .discloses((event, actor) =>\n * actor.id === event.stream || actor.roles?.includes(\"admin\"))\n * ```\n */\n discloses: (\n disclose: (\n event: Committed<TEvents, keyof TEvents & string>,\n actor: Actor\n ) => boolean\n ) => ActionBuilder<TState, TEvents, TActions, TName, TSnap>;\n /**\n * Declares the online close predicate for this state. The\n * orchestrator's autoclose cycle iterates the state's streams once\n * per tick and calls the predicate per candidate; truthy results are\n * scheduled for atomic truncate-and-seed via `Store.truncate` on the\n * next batch.\n *\n * One predicate per state. A second `.autocloses(...)` call replaces\n * the first (same shape as `.snap` / `.discloses` — state-level, not\n * per-event). Absent → the state opts out of online close entirely;\n * the cycle skips it and pays zero per-tick cost for it.\n *\n * Pass a declarative {@link AutoclosePolicy} object literal covering the\n * three operational pressure points (`after`, `is`, `reaches`). Top-level\n * fields combine with AND; an optional `or: {...}` block opens an\n * alternative OR path. Validated via Zod at build time; misconfiguration\n * throws before `act().build()` completes.\n *\n * Under the hood this compiles to a synthesized reaction (#1090) that runs\n * on a per-aggregate synthetic stream: it defers to `head.created + the\n * policy's min after` while the cooldown holds and closes the stream once\n * the policy matches. There is no background sweep.\n *\n * **The function-predicate form was removed (#1090).** `.autocloses` no\n * longer accepts `(stream, head, count) => boolean`; an opaque predicate has\n * no derivable due-time or terminal event to react to. For conditions the\n * declarative form can't express, call `app.close(...)` from your own logic.\n *\n * @param policy The declarative {@link AutoclosePolicy} bag.\n * @returns The ActionBuilder for chaining.\n *\n * @example Declarative — cooldown after terminal (a Ticket closes\n * 90 days after resolution).\n * ```typescript\n * .autocloses({ is: \"TicketResolved\", after: { days: 90 } })\n * ```\n *\n * @example Declarative — multi-terminal (an Order closes on any of\n * three terminal events, no cooldown).\n * ```typescript\n * .autocloses({ is: [\"Shipped\", \"Delivered\", \"Cancelled\"] })\n * ```\n *\n * @example Declarative — time-only retention (a Session closes\n * after 24h regardless of head event).\n * ```typescript\n * .autocloses({ after: { days: 1 } })\n * ```\n *\n * @example Declarative — pure cardinality cap.\n * ```typescript\n * .autocloses({ reaches: 10_000 })\n * ```\n *\n * @example Declarative — primary cooldown + safety-net backstop.\n * ```typescript\n * .autocloses({\n * is: \"TicketResolved\", // primary trigger\n * after: { days: 90 }, // AND aged 90 days\n * or: { reaches: 10_000 }, // OR cardinality safety net\n * })\n * ```\n *\n * @example Declarative — pure OR (only backstops, no primary\n * cooldown).\n * ```typescript\n * .autocloses({ or: { is: \"TicketResolved\", reaches: 10_000 } })\n * ```\n *\n * @example Rolling window — keep the last 180 days of real events on a\n * live stream (requires `.snap(...)` earlier in the chain; `keep`\n * won't typecheck without it). Each eligible cycle prunes the prefix\n * below the closest safe snapshot older than `now − keep`.\n * ```typescript\n * .snap((s) => s.patches >= 100)\n * .autocloses({ keep: { days: 180 } })\n * ```\n *\n * @example Terminate AND prune — close 90 days after resolution,\n * meanwhile keep open streams pruned to a 180-day window.\n * ```typescript\n * .snap((s) => s.patches >= 100)\n * .autocloses({ is: \"TicketResolved\", after: { days: 90 }, keep: { days: 180 } })\n * ```\n */\n autocloses: (\n policy: [TSnap] extends [true]\n ? AutoclosePolicy\n : Omit<AutoclosePolicy, \"keep\"> & {\n /** Rolling-window retention requires `.snap(...)` earlier in\n * the builder chain — a windowed close prunes behind a real\n * snapshot, so a state that never snapshots has nothing to\n * prune behind. */\n keep?: never;\n }\n ) => ActionBuilder<TState, TEvents, TActions, TName, TSnap>;\n /**\n * Declares the archiver the online close cycle runs **before**\n * truncating a stream this state's `.autocloses(...)` predicate\n * accepted. Hosts use it to write events to durable storage (S3,\n * an analytics warehouse, cold tier) before the tombstone lands,\n * so the truncate doesn't lose history that the operator still\n * needs.\n *\n * Threads into `CloseTarget.archive` via the same plumbing\n * `app.close({ stream, archive })` already uses — the cycle holds\n * the stream's guard while the archiver runs, and a thrown\n * archiver leaves the stream guarded but un-truncated. No partial\n * truncate state, no data loss; the cycle retries the candidate\n * on the next tick.\n *\n * One archiver per state. A second `.archives(...)` call replaces\n * the first (same shape as `.snap` / `.discloses` /\n * `.autocloses`). Absent → the cycle truncates without an archive\n * step.\n *\n * @param archive `(stream, head) => Promise<void>`. Runs while\n * the stream is locked against new writes; the truncate runs\n * immediately after a successful resolve.\n * @returns The ActionBuilder for chaining.\n *\n * @example Archive to S3 before truncate.\n * ```typescript\n * state({ Ticket: ticketSchema })\n * .emits({ TicketOpened, TicketResolved })\n * // ...\n * .autocloses({ is: \"TicketResolved\" })\n * .archives(async (stream) => {\n * const events = await loadEvents(stream);\n * await s3.upload(`tickets/${stream}.jsonl`, events);\n * })\n * ```\n */\n archives: (\n archive: AutocloseArchiver<TEvents>\n ) => ActionBuilder<TState, TEvents, TActions, TName, TSnap>;\n /**\n * Finalizes and builds the state definition.\n *\n * Call this method after defining all actions, invariants, and patches to create\n * the complete State object that can be registered with Act.\n *\n * @returns The complete strongly-typed State definition\n *\n * @example\n * ```typescript\n * const Counter = state({ Counter: schema })\n * .init(() => ({ count: 0 }))\n * .emits({ Incremented: z.object({ amount: z.number() }) })\n * .patch({ Incremented: ({ data }, state) => ({ count: state.count + data.amount }) })\n * .on({ increment: z.object({ by: z.number() }) })\n * .emit((action) => [\"Incremented\", { amount: action.by }])\n * .build(); // Returns State<TState, TEvents, TActions, TName>\n * ```\n */\n build: () => State<TState, TEvents, TActions, TName>;\n};\n\n/**\n * Creates a new state definition with event sourcing capabilities.\n *\n * States are the core building blocks of Act. Each state represents a consistency\n * boundary (aggregate) that processes actions, emits events, and maintains its own\n * state through event patches (reducers). States use event sourcing to maintain a\n * complete audit trail and enable time-travel capabilities.\n *\n * The state builder provides a fluent API for defining:\n * 1. Initial state via `.init()`\n * 2. Event types via `.emits()` — all events default to passthrough (`({ data }) => data`)\n * 3. Custom event reducers via `.patch()` (optional — only for events that need custom logic)\n * 4. Actions (commands) via `.on()` → `.emit()` — pass an event name string for passthrough\n * 5. Business rules (invariants) via `.given()`\n * 6. Snapshotting strategy via `.snap()`\n *\n * @template TState - Zod schema type defining the shape of the state\n * @param entry - Single-key record mapping state name to Zod schema (e.g., `{ Counter: z.object({ count: z.number() }) }`)\n * @returns A StateBuilder instance for fluent API configuration\n *\n * @example Basic counter state (with custom patch)\n * ```typescript\n * import { state } from \"@rotorsoft/act\";\n * import { z } from \"zod\";\n *\n * const Counter = state({ Counter: z.object({ count: z.number() }) })\n * .init(() => ({ count: 0 }))\n * .emits({\n * Incremented: z.object({ amount: z.number() })\n * })\n * .patch({ // optional — only for events needing custom reducers\n * Incremented: ({ data }, state) => ({ count: state.count + data.amount })\n * })\n * .on({ increment: z.object({ by: z.number() }) })\n * .emit((action) => [\"Incremented\", { amount: action.by }])\n * .build();\n * ```\n *\n * @example Passthrough state (no custom patch or emit needed)\n * ```typescript\n * const DigitBoard = state({ DigitBoard: z.object({ digit: z.string() }) })\n * .init(() => ({ digit: \"\" }))\n * .emits({ DigitCounted: z.object({ digit: z.string() }) })\n * // no .patch() — passthrough is the default (event data merges into state)\n * .on({ CountDigit: z.object({ digit: z.string() }) })\n * .emit(\"DigitCounted\") // string passthrough — action payload becomes event data\n * .build();\n * ```\n *\n * @example State with multiple events and invariants\n * ```typescript\n * const BankAccount = state({ BankAccount: z.object({\n * balance: z.number(),\n * currency: z.string(),\n * status: z.enum([\"open\", \"closed\"])\n * }) })\n * .init(() => ({ balance: 0, currency: \"USD\", status: \"open\" }))\n * .emits({\n * Deposited: z.object({ amount: z.number() }),\n * Withdrawn: z.object({ amount: z.number() }),\n * Closed: z.object({})\n * })\n * .patch({ // only override events needing custom logic\n * Deposited: ({ data }, state) => ({ balance: state.balance + data.amount }),\n * Withdrawn: ({ data }, state) => ({ balance: state.balance - data.amount }),\n * Closed: () => ({ status: \"closed\", balance: 0 })\n * })\n * .on({ deposit: z.object({ amount: z.number() }) })\n * .given([\n * { description: \"Account must be open\", valid: (state) => state.status === \"open\" }\n * ])\n * .emit(\"Deposited\") // passthrough — action payload { amount } becomes event data\n * .on({ withdraw: z.object({ amount: z.number() }) })\n * .given([\n * { description: \"Account must be open\", valid: (state) => state.status === \"open\" },\n * { description: \"Funds must be available\", valid: (state) => state.balance > 0 }\n * ])\n * .emit(\"Withdrawn\")\n * .on({ close: z.object({}) })\n * .given([\n * { description: \"Account must be open\", valid: (state) => state.status === \"open\" },\n * { description: \"Balance must be zero\", valid: (state) => state.balance === 0 }\n * ])\n * .emit(\"Closed\")\n * .build();\n * ```\n *\n * @example State with snapshotting\n * ```typescript\n * const User = state({ User: z.object({\n * name: z.string(),\n * email: z.string(),\n * loginCount: z.number()\n * }) })\n * .init((data) => ({ ...data, loginCount: 0 }))\n * .emits({\n * UserCreated: z.object({ name: z.string(), email: z.string() }),\n * UserLoggedIn: z.object({})\n * })\n * .patch({ // only override events needing custom logic\n * UserLoggedIn: (_, state) => ({ loginCount: state.loginCount + 1 })\n * })\n * // UserCreated uses passthrough — event data merges into state\n * .on({ createUser: z.object({ name: z.string(), email: z.string() }) })\n * .emit(\"UserCreated\") // passthrough\n * .on({ login: z.object({}) })\n * .emit(\"UserLoggedIn\")\n * .snap((snap) => snap.patches >= 10) // Snapshot every 10 events\n * .build();\n * ```\n *\n * @see {@link StateBuilder} for available builder methods\n * @see {@link ActionBuilder} for action configuration methods\n * @see {@link https://rotorsoft.github.io/act-root/docs/intro | Getting Started Guide}\n * @see {@link https://rotorsoft.github.io/act-root/docs/examples/calculator | Calculator Example}\n */\nexport function state<TName extends string, TState extends Schema>(\n entry: StateEntry<TName, TState>\n): StateBuilder<TState, TName> {\n const keys = Object.keys(entry);\n if (keys.length !== 1) throw new Error(\"state() requires exactly one key\");\n const name = keys[0] as TName;\n const state_schema = (entry as Record<string, ZodType<TState>>)[name];\n return {\n init(init) {\n return {\n emits<TEvents extends Schema>(events: ZodTypes<TEvents>) {\n // Default passthrough patches: event data merges into state\n const default_patch = Object.fromEntries(\n Object.keys(events).map((k) => {\n const fn = Object.assign(({ data }: { data: any }) => data, {\n _passthrough: true as const,\n }) satisfies PassthroughPatchHandler;\n return [k, fn];\n })\n ) as unknown as PatchHandlers<TState, TEvents>;\n\n // Build one mutable state object the action_builder threads\n // through every fluent call. patch() (if invoked) just mutates\n // the patch map in place — no re-builder wasted.\n const internal: State<TState, TEvents, Schemas, TName> = {\n events,\n actions: {},\n state: state_schema,\n name,\n init,\n patch: default_patch,\n on: {},\n // Step delegates initialized as identity, `pii_aware` false.\n // `act().build()` flips both on states with `sensitive(...)`\n // events to bake in the gate / split and gate the cache write.\n pii_aware: false,\n view: (event) => event,\n message: (validated) => validated,\n };\n\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- {} avoids string index signature\n const builder = action_builder<TState, TEvents, {}, TName>(internal);\n\n return Object.assign(builder, {\n patch(customPatch: Partial<PatchHandlers<TState, TEvents>>) {\n Object.assign(internal.patch, customPatch);\n return builder;\n },\n });\n },\n };\n },\n };\n}\n\n/**\n * Internal action-builder. The runtime object is a single mutable bag —\n * each fluent call (`on`, `snap`) mutates it and returns the same builder\n * cast to the widened generic type. Type-level fanout is preserved; the\n * O(N) `{...state}` spreads per call are not.\n *\n * Generics are erased to `Schemas` at runtime — the cast on return narrows\n * back to the call-site's widened types.\n */\nfunction action_builder<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TName extends string = string,\n>(\n state: State<TState, TEvents, TActions, TName>\n): ActionBuilder<TState, TEvents, TActions, TName> {\n // The mutable bag — typed loosely since callers narrow on return.\n const internal = state as unknown as State<TState, TEvents, Schemas, TName>;\n\n const builder: ActionBuilder<TState, TEvents, TActions, TName> = {\n on<TKey extends string, TNewActions extends Schema>(\n entry: ActionEntry<TKey, TNewActions>,\n options?: ActionOptions\n ) {\n const keys = Object.keys(entry);\n if (keys.length !== 1) throw new Error(\".on() requires exactly one key\");\n const action = keys[0] as TKey;\n const schema = entry[action];\n\n if (action in internal.actions)\n throw new Error(`Duplicate action \"${action}\"`);\n\n type MergedActions = TActions & { [P in TKey]: TNewActions };\n (internal.actions as Record<string, ZodType<Schema>>)[action] = schema;\n if (options) {\n // #1269: validate the whole action bag at declaration so a bad\n // `maxRetries`/`backoff` throws ZodError at build, not a NaN gate.\n resolveActionConfig(options);\n internal.options ??= {};\n (internal.options as Record<string, ActionOptions>)[action] = options;\n }\n\n function given(rules: Invariant<TState>[]) {\n internal.given ??= {} as GivenHandlers<TState, Schemas>;\n (internal.given as Record<string, Invariant<TState>[]>)[action] = rules;\n return { emit };\n }\n\n function emit(\n handler:\n | ActionHandler<TState, TEvents, MergedActions, TKey>\n | (keyof TEvents & string)\n ) {\n if (typeof handler === \"string\") {\n const event_name = handler;\n // Tag the synthetic function with the static event name so\n // the act-builder can detect emissions of deprecated events\n // at build time (ACT-403). Dynamic forms — where the\n // returned event name is computed inside the user's\n // function — can't be inspected statically; they're caught\n // by the runtime warning in event-sourcing.ts.\n const emit_fn = Object.assign(\n (payload: any) => [event_name, payload],\n {\n _static_emit: event_name,\n }\n );\n (internal.on as Record<string, unknown>)[action] = emit_fn;\n } else {\n (internal.on as Record<string, unknown>)[action] = handler;\n }\n return builder as unknown as ActionBuilder<\n TState,\n TEvents,\n MergedActions,\n TName\n >;\n }\n\n return { given, emit };\n },\n\n snap(snap: (snapshot: Snapshot<TState, TEvents>) => boolean) {\n internal.snap = snap;\n // Flip the type-level TSnap flag — same runtime object, the cast\n // unlocks `.autocloses({ keep })` for the rest of the chain.\n return builder as unknown as ActionBuilder<\n TState,\n TEvents,\n TActions,\n TName,\n true\n >;\n },\n\n discloses(\n disclose: (\n event: Committed<TEvents, keyof TEvents & string>,\n actor: Actor\n ) => boolean\n ) {\n // Replace on every call — matches snap's state-level semantics. Operators\n // who need per-event differences branch inside the predicate.\n internal.disclose = disclose;\n return builder;\n },\n\n autocloses(policy: AutoclosePolicy) {\n // Declarative policy only (#1090). The online path is a synthesized\n // reaction that defers to a derivable due-time and closes — an opaque\n // function predicate has no terminal event to react to nor a window to\n // derive, so it's no longer accepted online. Operators who need custom\n // logic call `app.close(...)` from their own reaction.\n if (typeof policy === \"function\") {\n throw new Error(\n \".autocloses(fn) is no longer supported — pass a declarative policy \" +\n \"({ after, is, reaches, or }) or call app.close(...) from your own \" +\n \"reaction for custom logic.\"\n );\n }\n if (policy === null || typeof policy !== \"object\") {\n throw new Error(\n \".autocloses(...) requires a policy object; got \" + typeof policy\n );\n }\n // The type gate (`TSnap`) already rejects `keep` before `.snap` at\n // compile time; this is the equivalent guard for untyped callers.\n if ((policy as AutoclosePolicy).keep && !internal.snap) {\n throw new Error(\n \".autocloses({ keep }) requires .snap(...) earlier in the chain — a rolling window prunes behind a real snapshot, so a state that never snapshots has nothing to prune behind.\"\n );\n }\n // Replace on every call — matches snap / discloses state-level\n // semantics. Compile to the predicate the reaction evaluates, and\n // cache the policy's min `after` window so the reaction knows whether\n // to park on a due-time or wait for the next event; `keep` resolves\n // to the rolling-window width the reaction prunes against.\n internal.autoclose = compile_autoclose_policy(\n policy\n ) as AutoclosePredicate<TEvents>;\n internal.autoclose_after_days = policy_min_after_days(policy);\n internal.autoclose_keep_days = policy_keep_days(policy);\n return builder;\n },\n\n archives(archive: AutocloseArchiver<TEvents>) {\n if (typeof archive !== \"function\") {\n throw new Error(\n \".archives(archive) requires a function; got \" + typeof archive\n );\n }\n internal.archive = archive;\n return builder;\n },\n\n build(): State<TState, TEvents, TActions, TName> {\n return internal as unknown as State<TState, TEvents, TActions, TName>;\n },\n };\n return builder;\n}\n","/**\n * @module csv\n *\n * `CsvFile` — a single class implementing both {@link EventSource}\n * and {@link EventSink} so a CSV file on disk can be either side of\n * a transfer pipeline (ACT-1128 / #788).\n *\n * - As a source: streams one row at a time off a line interface;\n * the awaited per-event callback gives 1-event-in-flight\n * backpressure on reads.\n * - As a sink: serialized `WriteStream.write` await per row,\n * propagating I/O errors through the chunk callback.\n *\n * `commit` / `claim` / `subscribe` and the rest of `Store` are NOT\n * implemented — `CsvFile` is a transfer-only primitive, not a\n * store you'd run an Act app against.\n */\n\nimport { createReadStream, createWriteStream, type WriteStream } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport type {\n Committed,\n EventSink,\n EventSource,\n Query,\n Schemas,\n} from \"./types/action.js\";\nimport { dateReviver } from \"./utils.js\";\n\n/**\n * Construct a {@link CsvFile} from either a filesystem path (for\n * reading and/or writing through the OS) or an in-memory blob (a\n * pre-loaded CSV string, used by the inspector when a CSV arrives\n * over the wire via tRPC).\n *\n * Both modes share the same on-disk format, so the same blob shape\n * can be round-tripped through the transfer pipeline.\n */\nexport type CsvFileOptions = { path: string } | { blob: string };\n\n/**\n * Same column order as the inspector's backup endpoint, kept here\n * so `CsvFile` is round-trip-compatible with existing backups.\n */\nconst CSV_COLUMNS = [\n \"id\",\n \"name\",\n \"data\",\n \"stream\",\n \"version\",\n \"created\",\n \"meta\",\n] as const;\n\nexport class CsvFile implements EventSource, EventSink {\n private readonly path: string | null;\n private readonly blob: string | null;\n\n constructor(options: CsvFileOptions) {\n if (\"path\" in options) {\n this.path = options.path;\n this.blob = null;\n } else {\n this.path = null;\n this.blob = options.blob;\n }\n }\n\n async query<E extends Schemas>(\n callback: (event: Committed<E, keyof E>) => void,\n _filter?: Query\n ): Promise<number> {\n const lines =\n this.blob !== null ? linesFromBlob(this.blob) : linesFromFile(this.path!);\n let count = 0;\n let header: readonly string[] | null = null;\n for await (const line of lines) {\n if (!line.trim()) continue;\n const fields = parse_csv_line(line);\n if (!header) {\n header = fields;\n const expected = CSV_COLUMNS.join(\",\");\n if (header.join(\",\") !== expected)\n throw new Error(`Invalid CSV header. Expected: ${expected}`);\n continue;\n }\n if (fields.length !== CSV_COLUMNS.length)\n throw new Error(\n `Row ${count + 1}: expected ${CSV_COLUMNS.length} fields, got ${fields.length}`\n );\n const event: Committed<E, keyof E> = {\n id: Number.parseInt(fields[0]!, 10),\n name: fields[1]! as keyof E,\n // Revive dates like every Store adapter does — a Date in an event\n // payload must not depend on whether it came back through a store or\n // through a CSV restore (#1399). The `created` column below has\n // always been parsed explicitly; the JSON columns were missed.\n data: JSON.parse(fields[2]!, dateReviver),\n stream: fields[3]!,\n version: Number.parseInt(fields[4]!, 10),\n created: new Date(fields[5]!),\n meta: JSON.parse(fields[6]!, dateReviver),\n };\n await Promise.resolve(callback(event));\n count++;\n }\n if (header === null)\n throw new Error(\"CSV must have a header and at least one row\");\n return count;\n }\n\n async restore(\n driver: (\n callback: (event: Committed<Schemas, keyof Schemas>) => Promise<number>\n ) => Promise<void>\n ): Promise<void> {\n if (this.path === null)\n throw new Error(\n \"CsvFile in blob mode is read-only — provide `path` to write\"\n );\n const writer = createWriteStream(this.path, {\n flags: \"w\",\n encoding: \"utf8\",\n });\n let next_id = 1;\n try {\n await write_line(writer, CSV_COLUMNS.join(\",\"));\n await driver(async (event) => {\n const id = next_id++;\n const row = [\n String(id),\n csv_escape(event.name as string),\n csv_escape(JSON.stringify(event.data)),\n csv_escape(event.stream),\n String(event.version),\n event.created.toISOString(),\n csv_escape(JSON.stringify(event.meta)),\n ].join(\",\");\n await write_line(writer, row);\n return id;\n });\n } finally {\n await new Promise<void>((resolve) => writer.end(resolve));\n }\n }\n\n async dispose(): Promise<void> {\n // No-op: `restore` always closes its writer in a `finally`, and\n // blob mode never opens one. The Disposable contract is here to\n // make `CsvFile` interchangeable with `Store` in transfer\n // pipelines, not because the file handle outlives the call.\n }\n}\n\nasync function* linesFromFile(path: string): AsyncIterable<string> {\n const stream = createReadStream(path, { encoding: \"utf8\" });\n const rl = createInterface({\n input: stream,\n crlfDelay: Number.POSITIVE_INFINITY,\n });\n try {\n for await (const line of rl) yield line;\n } finally {\n rl.close();\n stream.close();\n }\n}\n\nasync function* linesFromBlob(blob: string): AsyncIterable<string> {\n let start = 0;\n while (start < blob.length) {\n const nl = blob.indexOf(\"\\n\", start);\n const end = nl === -1 ? blob.length : nl;\n yield blob.slice(start, end);\n start = nl === -1 ? blob.length : nl + 1;\n await Promise.resolve();\n }\n}\n\nfunction parse_csv_line(line: string): string[] {\n const fields: string[] = [];\n let i = 0;\n while (i < line.length) {\n if (line[i] === '\"') {\n let value = \"\";\n i++;\n while (i < line.length) {\n if (line[i] === '\"' && line[i + 1] === '\"') {\n value += '\"';\n i += 2;\n } else if (line[i] === '\"') {\n i++;\n break;\n } else {\n value += line[i++];\n }\n }\n fields.push(value);\n if (line[i] === \",\") i++;\n } else {\n const next = line.indexOf(\",\", i);\n if (next === -1) {\n fields.push(line.slice(i));\n i = line.length;\n } else {\n fields.push(line.slice(i, next));\n i = next + 1;\n }\n }\n }\n return fields;\n}\n\nfunction csv_escape(value: string): string {\n if (/[\",\\n\\r]/.test(value)) return `\"${value.replace(/\"/g, '\"\"')}\"`;\n return value;\n}\n\nfunction write_line(writer: WriteStream, line: string): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n writer.write(`${line}\\n`, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n"],"mappings":"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","names":["store","state","sensitive","deps","config","z","z","z","z","state","config","config","tombstone","load","snap","state","state","action","state","action","valid","action","block","config","cache","row","block","action","action","state","config","config","state","config","state","action","snap"]}