@rotorsoft/act 1.32.14 → 1.32.16

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.
Files changed (74) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/@types/act.d.ts +98 -152
  3. package/dist/@types/act.d.ts.map +1 -1
  4. package/dist/@types/adapters/in-memory-store.d.ts +3 -3
  5. package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
  6. package/dist/@types/builders/act-builder.d.ts +3 -3
  7. package/dist/@types/builders/act-builder.d.ts.map +1 -1
  8. package/dist/@types/builders/build-classify.d.ts +1 -1
  9. package/dist/@types/builders/builder-base.d.ts +3 -3
  10. package/dist/@types/builders/builder-utils.d.ts +1 -1
  11. package/dist/@types/builders/event-builder.d.ts +1 -1
  12. package/dist/@types/builders/merge.d.ts +1 -1
  13. package/dist/@types/builders/reaction-builder.d.ts +1 -1
  14. package/dist/@types/builders/slice-builder.d.ts +2 -2
  15. package/dist/@types/builders/state-builder.d.ts +3 -4
  16. package/dist/@types/builders/state-builder.d.ts.map +1 -1
  17. package/dist/@types/csv.d.ts +1 -1
  18. package/dist/@types/disposers.d.ts.map +1 -1
  19. package/dist/@types/internal/audit.d.ts +12 -42
  20. package/dist/@types/internal/audit.d.ts.map +1 -1
  21. package/dist/@types/internal/autoclose-policy.d.ts +3 -3
  22. package/dist/@types/internal/autoclose-reaction.d.ts +2 -2
  23. package/dist/@types/internal/autoclose-window.d.ts +1 -1
  24. package/dist/@types/internal/close-cycle.d.ts +10 -31
  25. package/dist/@types/internal/close-cycle.d.ts.map +1 -1
  26. package/dist/@types/internal/close-signal.d.ts +3 -3
  27. package/dist/@types/internal/config.d.ts +3 -3
  28. package/dist/@types/internal/config.d.ts.map +1 -1
  29. package/dist/@types/internal/correlate-cycle.d.ts +39 -86
  30. package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
  31. package/dist/@types/internal/correlator.d.ts +1 -1
  32. package/dist/@types/internal/date-reviver.d.ts +1 -1
  33. package/dist/@types/internal/defer-config.d.ts +2 -2
  34. package/dist/@types/internal/defer-signal.d.ts +2 -2
  35. package/dist/@types/internal/defer-timer.d.ts +3 -3
  36. package/dist/@types/internal/drain-cycle.d.ts +44 -88
  37. package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
  38. package/dist/@types/internal/event-sourcing.d.ts +8 -19
  39. package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
  40. package/dist/@types/internal/event-versions.d.ts +1 -1
  41. package/dist/@types/internal/projection-fold.d.ts +2 -2
  42. package/dist/@types/internal/report-once.d.ts +3 -3
  43. package/dist/@types/internal/sensitive.d.ts +2 -2
  44. package/dist/@types/internal/settle.d.ts +6 -19
  45. package/dist/@types/internal/settle.d.ts.map +1 -1
  46. package/dist/@types/ports.d.ts +3 -3
  47. package/dist/@types/scoped.d.ts +6 -6
  48. package/dist/@types/scoped.d.ts.map +1 -1
  49. package/dist/@types/types/action.d.ts +23 -25
  50. package/dist/@types/types/action.d.ts.map +1 -1
  51. package/dist/@types/types/audit.d.ts +1 -1
  52. package/dist/@types/types/ports.d.ts +22 -26
  53. package/dist/@types/types/ports.d.ts.map +1 -1
  54. package/dist/@types/types/reaction.d.ts +15 -20
  55. package/dist/@types/types/reaction.d.ts.map +1 -1
  56. package/dist/@types/types/registry.d.ts +1 -1
  57. package/dist/@types/types/schemas.d.ts +2 -2
  58. package/dist/@types/utils.d.ts +1 -1
  59. package/dist/{chunk-FVJFR7GH.js → chunk-JRTZGWVS.js} +1 -1
  60. package/dist/chunk-JRTZGWVS.js.map +1 -0
  61. package/dist/{chunk-JPPO3LZ3.js → chunk-PZP5ZEZ4.js} +9 -9
  62. package/dist/chunk-PZP5ZEZ4.js.map +1 -0
  63. package/dist/index.cjs +152 -372
  64. package/dist/index.cjs.map +1 -1
  65. package/dist/index.js +147 -367
  66. package/dist/index.js.map +1 -1
  67. package/dist/test/index.cjs +7 -7
  68. package/dist/test/index.cjs.map +1 -1
  69. package/dist/test/index.js +2 -2
  70. package/dist/types/index.cjs.map +1 -1
  71. package/dist/types/index.js +1 -1
  72. package/package.json +1 -1
  73. package/dist/chunk-FVJFR7GH.js.map +0 -1
  74. package/dist/chunk-JPPO3LZ3.js.map +0 -1
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  sleep,
27
27
  store,
28
28
  validate
29
- } from "./chunk-JPPO3LZ3.js";
29
+ } from "./chunk-PZP5ZEZ4.js";
30
30
  import {
31
31
  ActorSchema,
32
32
  CausationEventSchema,
@@ -53,7 +53,7 @@ import {
53
53
  pii_split,
54
54
  pii_strip,
55
55
  sensitive
56
- } from "./chunk-FVJFR7GH.js";
56
+ } from "./chunk-JRTZGWVS.js";
57
57
 
58
58
  // src/signals.ts
59
59
  process.once("SIGINT", async (arg) => {
@@ -835,7 +835,7 @@ var CloseSignal = class extends Error {
835
835
  */
836
836
  at;
837
837
  /**
838
- * Windowed close (#1011): prune events older than this cutoff behind
838
+ * Windowed close: prune events older than this cutoff behind
839
839
  * the closest safe snapshot instead of retiring the stream. Thrown by
840
840
  * the autoclose reaction of a `.autocloses({ keep })` state; flows
841
841
  * into {@link CloseTarget.before}. Omitted → a full close.
@@ -913,7 +913,7 @@ var SettleOptionsSchema = DrainOptionsSchema.extend({
913
913
  // rejects `±Infinity`, and an integer check cannot pass it either. Wrapper
914
914
  // code normalizing an optional cap (`maxPasses: opts.maxPasses ?? Infinity`)
915
915
  // is the natural way to hit it. Accepting it also honors this module's own
916
- // rule that a value which works today is never newly rejected (#1711).
916
+ // rule that a value which works today is never newly rejected.
917
917
  maxPasses: z2.union([z2.number().int().min(0), z2.literal(Number.POSITIVE_INFINITY)]).optional()
918
918
  }).loose();
919
919
  function resolveSettleConfig(options) {
@@ -1555,7 +1555,7 @@ var CorrelateCycle = class {
1555
1555
  _checkpoint = -1;
1556
1556
  _initialized = false;
1557
1557
  /**
1558
- * This worker's identity for the correlation lease (#1532). A per-instance
1558
+ * This worker's identity for the correlation lease. A per-instance
1559
1559
  * UUID, matching the drain's convention, so a renewal is recognised as the
1560
1560
  * same holder and a restarted process never inherits a stale claim.
1561
1561
  */
@@ -1571,24 +1571,15 @@ var CorrelateCycle = class {
1571
1571
  * When this worker's correlation lease runs out, as a local clock reading,
1572
1572
  * or 0 when it holds none.
1573
1573
  *
1574
- * Asking the store on every pass costs a round trip that the holder — which
1575
- * is the *only* worker in a single-node deployment, and the steady-state
1576
- * one everywhere else — gains nothing from: it already knows the answer.
1577
- * The act-sqlite perf gate caught that as a 1.5x regression on
1578
- * correlate+drain, which is the shape an embedded app runs constantly.
1579
- *
1580
- * Believing this while the store disagrees is safe in the one direction it
1581
- * can fail. A worker that scans without really holding the lease produces
1582
- * the duplicate scan that existed before the lease, and the marks are
1583
- * idempotent — so a stale belief costs work, never correctness.
1574
+ * Cached so the holder doesn't ask the store on every pass. A stale belief
1575
+ * can only cause a duplicate scan, and marks are idempotent, so it costs
1576
+ * work, never correctness.
1584
1577
  */
1585
1578
  _lease_until = 0;
1586
1579
  /**
1587
- * Whether a scan might find anything. The drain has carried the same flag
1588
- * since it was written — a commit raises it, an empty claim lowers it, and
1589
- * a disarmed drain returns without touching the store. Correlate had no
1590
- * equivalent, so a settle pass always scanned, including the final pass
1591
- * whose only job is to confirm nothing changed (#1510).
1580
+ * Whether a scan might find anything, like the drain's flag: a commit or
1581
+ * notification raises it, a short page lowers it, and a disarmed scan
1582
+ * returns without touching the store.
1592
1583
  *
1593
1584
  * Starts armed: the log may already hold events this process has never
1594
1585
  * correlated, and only a scan can find out.
@@ -1597,15 +1588,9 @@ var CorrelateCycle = class {
1597
1588
  /** In-flight init, memoized for single-flight and cleared on failure. */
1598
1589
  _init_promise;
1599
1590
  // Dynamically discovered targets → what each was last subscribed at,
1600
- // bounded by `maxSubscribedStreams`. The static half lives in
1601
- // `_static_subscriptions` below, which is deliberately not evictable.
1602
- //
1603
- // Every scan re-subscribes the
1604
- // targets it resolved (that is how the work mark lands), so this no longer
1605
- // decides *whether* a target is sent — it decides *what* is sent with it:
1606
- // a resolution raises priority/lane only when it beats the recorded floor,
1607
- // and otherwise re-sends the row's own values so the mark changes nothing
1608
- // else. See {@link Subscription}.
1591
+ // bounded by `maxSubscribedStreams`. It decides *what* a scan sends with a
1592
+ // target: priority/lane only when the resolution beats the recorded floor,
1593
+ // otherwise the row's own values. See {@link Subscription}.
1609
1594
  _dynamic_subscriptions;
1610
1595
  /**
1611
1596
  * What each static target was subscribed at by `init`. A plain map, never
@@ -1613,14 +1598,8 @@ var CorrelateCycle = class {
1613
1598
  * is already bounded by the registry and costs nothing the registry does
1614
1599
  * not already hold.
1615
1600
  *
1616
- * Keeping these out of the LRU is what makes the `+Infinity` floor an
1617
- * invariant rather than a race (#1582). Sharing the bounded map meant a
1618
- * churn of dynamic targets could evict a static record, and the next
1619
- * dynamic resolution to that target found no record, took the
1620
- * first-discovery branch, and re-subscribed the target with its own
1621
- * priority and lane — silently re-laning a stream whose lane the
1622
- * build-time subscribe owns, and starving it wherever `onlyLanes` had
1623
- * provisioned a worker for the declared lane.
1601
+ * Kept out of the LRU so eviction can never drop a static target's
1602
+ * `+Infinity` floor and let a dynamic resolution re-lane it.
1624
1603
  */
1625
1604
  _static_subscriptions = /* @__PURE__ */ new Map();
1626
1605
  /** Compiled pattern sources, bounded by {@link PATTERN_CACHE_SIZE}. */
@@ -1630,17 +1609,13 @@ var CorrelateCycle = class {
1630
1609
  _cd;
1631
1610
  _on_init;
1632
1611
  /**
1633
- * Async cold-start hook (#1221). Runs once, after the sync `on_init`,
1634
- * inside the same `init()` await. The orchestrator uses it to re-seed the
1635
- * process-local defer timers from the store's persisted `deferred_at` so
1636
- * an idle deferred stream re-arms its drain across a restart. Kept
1637
- * separate from `on_init` because seeding is an async store read; `init`
1638
- * already awaits, so folding it in here preserves the "runs exactly once"
1639
- * guarantee without a second gate on the Act side.
1612
+ * Async cold-start hook, run once after `on_init` inside `init()`. The
1613
+ * orchestrator re-seeds its defer timers from the persisted `deferred_at`
1614
+ * here, so an idle deferred stream re-arms across a restart.
1640
1615
  */
1641
1616
  _on_init_async;
1642
1617
  /**
1643
- * Tail re-scan window applied to the cold-start checkpoint (ACT-1207).
1618
+ * Tail re-scan window applied to the cold-start checkpoint.
1644
1619
  * See {@link DEFAULT_COLD_START_BACK_SCAN}. Constructor arg (not a
1645
1620
  * public option) so tests can shrink it; defaults otherwise.
1646
1621
  */
@@ -1692,7 +1667,7 @@ var CorrelateCycle = class {
1692
1667
  * - Reads the durable correlate checkpoint (and max(at)) from the store,
1693
1668
  * flooring a first boot at `watermark - back_scan` so an event
1694
1669
  * committed-but-not-correlated before a crash is re-scanned on
1695
- * restart instead of skipped (ACT-1207)
1670
+ * restart instead of skipped
1696
1671
  * - Subscribes static resolver targets (idempotent upsert)
1697
1672
  * - Populates the subscribed-streams LRU
1698
1673
  * - Fires `on_init` once (Act uses this to flag a cold-start drain)
@@ -1709,7 +1684,7 @@ var CorrelateCycle = class {
1709
1684
  this._initialized = true;
1710
1685
  }
1711
1686
  async _run_init() {
1712
- const { watermark, correlated_at } = await store().subscribe([
1687
+ const { watermark, correlated_at } = await this._cd.subscribe([
1713
1688
  ...this._static_targets
1714
1689
  ]);
1715
1690
  this._checkpoint = correlated_at >= 0 ? correlated_at : Math.max(-1, watermark - this._cold_start_back_scan);
@@ -1723,21 +1698,6 @@ var CorrelateCycle = class {
1723
1698
  }
1724
1699
  await this._on_init_async?.();
1725
1700
  }
1726
- /**
1727
- * Forget targets whose subscription rows no longer exist, so a later
1728
- * scan can re-subscribe them.
1729
- *
1730
- * A full close deletes the closed stream's subscription row. The
1731
- * in-process dedup would otherwise still believe the target is
1732
- * subscribed and never re-issue `subscribe()`, silently stopping
1733
- * delivery for any reaction whose target is named after the stream —
1734
- * the documented per-aggregate shape `.to(e => ({target: e.stream}))`
1735
- * makes those two namespaces collide by construction (#1398).
1736
- *
1737
- * Static targets are left alone: their record lives in
1738
- * `_static_subscriptions`, which this never touches, so they stay pinned
1739
- * at +Infinity and the dynamic path never re-opens them.
1740
- */
1741
1701
  /**
1742
1702
  * Start correlation over after the event log was replaced wholesale
1743
1703
  * (`restore`). The restored log is renumbered from the start and its
@@ -1746,7 +1706,7 @@ var CorrelateCycle = class {
1746
1706
  * and the init latch makes the next pass run cold-start again: static
1747
1707
  * targets are re-subscribed, the checkpoint is re-read from the store
1748
1708
  * (which `restore` reset), and dynamic targets are rediscovered by the
1749
- * scan (#1772).
1709
+ * scan.
1750
1710
  */
1751
1711
  restart() {
1752
1712
  this._initialized = false;
@@ -1756,6 +1716,11 @@ var CorrelateCycle = class {
1756
1716
  this._static_subscriptions.clear();
1757
1717
  this._armed = true;
1758
1718
  }
1719
+ /**
1720
+ * Forget dynamic targets whose subscription rows no longer exist (a full
1721
+ * close deletes the row), so a later scan re-subscribes them. Static
1722
+ * targets keep their records.
1723
+ */
1759
1724
  forget_subscribed(streams) {
1760
1725
  for (const stream of streams) this._dynamic_subscriptions.delete(stream);
1761
1726
  }
@@ -1780,7 +1745,7 @@ var CorrelateCycle = class {
1780
1745
  * Scan the events past the checkpoint, resolve each to its target
1781
1746
  * streams, and record what it found through `cd.subscribe` — new dynamic
1782
1747
  * targets get registered, and every target an event resolved to gets its
1783
- * **work mark** raised to that event's id (#1487).
1748
+ * **work mark** raised to that event's id.
1784
1749
  *
1785
1750
  * Both resolver kinds are walked. A static target is already subscribed
1786
1751
  * at init, but marking it is what makes it claimable without probing the
@@ -1867,18 +1832,10 @@ var CorrelateCycle = class {
1867
1832
  }
1868
1833
  }
1869
1834
  },
1870
- // Decline the sensitive payload: this scan reads `name`/`stream`/`id`
1871
- // to resolve reaction targets and throws the rest away. Asking for a
1872
- // payload it discards made one unreadable row stop EVERY stream's
1873
- // reactions — correlate is the sole producer of the work mark, so a
1874
- // decrypt failure here strands the whole app with nothing blocked and
1875
- // nothing naming the row (#1675).
1876
- //
1877
- // A dynamic `.to(event => …)` resolver therefore sees `pii: null`.
1878
- // That is deliberate and is itself a fix: correlate runs actor-less,
1879
- // so handing a resolver decrypted plaintext is un-gated disclosure —
1880
- // the defect #1673 corrected on the drain return and #1277 before it.
1881
- // `data` already carries no sensitive keys; nothing merges them here.
1835
+ // Decline the sensitive payload: the scan only needs name/stream/id,
1836
+ // and one undecryptable row would otherwise stop every stream's
1837
+ // reactions. Resolvers therefore see `pii: null`; correlate runs
1838
+ // actor-less, so plaintext here would be un-gated disclosure.
1882
1839
  { ...query, after, with_pii: false }
1883
1840
  );
1884
1841
  const streams = [];
@@ -1922,18 +1879,9 @@ var CorrelateCycle = class {
1922
1879
  /**
1923
1880
  * Hand the correlation lease back early.
1924
1881
  *
1925
- * There is no release verb on the port, deliberately — expiry is the only
1926
- * path, which keeps a crash and a clean stop on the same code path. A
1927
- * holder can still shorten its own lease, because re-acquiring as the same
1928
- * holder renews, and renewing to a millisecond is a release in all but
1929
- * name.
1930
- *
1931
- * Without this a worker that stops cleanly still blocks discovery for the
1932
- * rest of its lease — invisible in a long-lived deployment, very visible
1933
- * anywhere Acts are created and dropped inside one process.
1934
- *
1935
- * Best-effort: failing here costs the lease's remaining lifetime, which is
1936
- * what would have happened had the process died instead.
1882
+ * The port has no release verb; re-acquiring as the same holder with a
1883
+ * zero duration releases it. Best-effort: a failure costs the lease's
1884
+ * remaining lifetime, as a crash would.
1937
1885
  */
1938
1886
  async release_correlation() {
1939
1887
  try {
@@ -2419,26 +2367,11 @@ async function load(me, target, callback, patch_fn = bare_patch) {
2419
2367
  {
2420
2368
  stream,
2421
2369
  stream_exact: true,
2422
- // The snapshot resume floor is a current-state optimization: it only
2423
- // holds when the load has no window of its own. `time_travel` already
2424
- // captures that (any `asOf` bound set), so request `with_snaps` only for
2425
- // a non-time-travel cold load — a bounded load full-scans real events
2426
- // under its `asOf` filter. This is the single floor-eligibility decision
2427
- // for the whole system; the stores apply the floor whenever asked and
2428
- // never re-derive it (RFC 1274).
2429
- //
2430
- // The warm path resumes from `after`, and MUST also carry `with_snaps`
2431
- // (#1345): `after` and `with_snaps` are independent store conditions —
2432
- // `after` bounds the scan (id > cached.event_id), `with_snaps` keeps
2433
- // `__snapshot__` rows in the result. A stale (lagging/cross-process)
2434
- // cache checkpoint can sit below a newer `__snapshot__` boundary, and a
2435
- // windowed close (`app.close`/`.autocloses({keep})`) may have pruned the
2436
- // domain events between the checkpoint and that snapshot. Without
2437
- // `with_snaps` the rebaselining snapshot is filtered out and the fold
2438
- // silently applies the surviving tail on top of stale state (wrong
2439
- // count, yet `version` still reports the true head — the concurrency
2440
- // guard passes). With it, the snapshot in the after-window rebaselines
2441
- // the fold; when no snapshot falls in the window it is a no-op.
2370
+ // `with_snaps` on every non-time-travel load. Cold, it resumes from the
2371
+ // latest snapshot (this is the only place that decides it; stores just
2372
+ // apply it). Warm, it keeps a snapshot above a stale checkpoint in the
2373
+ // result, so a windowed close that pruned the events in between can't
2374
+ // make the fold apply the tail onto stale state.
2442
2375
  ...cached ? { after: cached.event_id, with_snaps: true } : { ...time_travel ? {} : { with_snaps: true }, ...asOf }
2443
2376
  }
2444
2377
  );
@@ -2465,7 +2398,7 @@ async function load(me, target, callback, patch_fn = bare_patch) {
2465
2398
  // Head event id, captured atomically with `state`: the last replayed
2466
2399
  // event's id on a cache miss, or the cached checkpoint's event_id on a
2467
2400
  // warm hit with no new events. Consumers read this instead of a
2468
- // separate cache lookup that could race a concurrent commit (ACT-1204).
2401
+ // separate cache lookup that could race a concurrent commit.
2469
2402
  id: event?.id ?? cached?.event_id ?? -1,
2470
2403
  patches,
2471
2404
  snaps,
@@ -2543,14 +2476,8 @@ async function action(me, action2, target, payload, options, patch_fn = bare_pat
2543
2476
  stream,
2544
2477
  emitted,
2545
2478
  meta,
2546
- // Reactions skip the INFERRED guard: they always append against the
2547
- // current head. Stream leasing already serializes concurrent reactions,
2548
- // and forcing version checks here would turn ordinary catch-up into
2549
- // spurious retries. An expectedVersion the caller passed explicitly is
2550
- // still honored — dropping a guard the caller asked for is silent data
2551
- // loss, and the reaction context can reach further than the handler
2552
- // (detached timers, settle cycles) where the caller never intended a
2553
- // reaction's semantics at all.
2479
+ // Reactions skip the inferred version guard (leases already
2480
+ // serialize them); an explicit expectedVersion is still honored.
2554
2481
  reactingTo ? expectedVersion : expected
2555
2482
  );
2556
2483
  } catch (error) {
@@ -2829,7 +2756,16 @@ function warn_misrouted(seen, stream, handler, event) {
2829
2756
  `Reaction "${handler}" on "${event}" resolved to target "${stream}", which a projection already serves. A target is served by one batch handler or one state projection, so this reaction can never run \u2014 and delivering to it would hand the projection an aggregate from another stream. Skipping it. The equivalent static \`.to({ target })\` is rejected at build; a dynamic resolver's target is only knowable here.`
2830
2757
  );
2831
2758
  }
2832
- async function run_drain_cycle(ops, registry, batch_handlers, misrouted, store_failing, handle, handle_batch, lagging, leading, eventLimit, leaseMillis, on_blocked, lane) {
2759
+ async function run_drain_cycle(deps, cycle) {
2760
+ const { ops, registry, batch_handlers, handle, handle_batch, lane } = deps;
2761
+ const {
2762
+ lagging,
2763
+ leading,
2764
+ eventLimit,
2765
+ leaseMillis,
2766
+ misrouted,
2767
+ store_failing
2768
+ } = cycle;
2833
2769
  const leased = await ops.claim(
2834
2770
  lagging,
2835
2771
  leading,
@@ -2901,7 +2837,7 @@ async function run_drain_cycle(ops, registry, batch_handlers, misrouted, store_f
2901
2837
  const blocked = await ops.block(
2902
2838
  handled.filter(({ block: block2 }) => block2).map(({ lease, error }) => ({ ...lease, error }))
2903
2839
  );
2904
- if (blocked.length) on_blocked(blocked);
2840
+ if (blocked.length) deps.on_blocked(blocked);
2905
2841
  const submitted = handled.flatMap((h, i) => {
2906
2842
  const advance = h.handled > 0 ? h.acked_at : leased[i].at;
2907
2843
  return h.defer !== void 0 ? { ...h.lease, at: advance, due: h.defer, retry: -1 } : h.next_attempt_at !== void 0 ? { ...h.lease, at: advance, due: h.next_attempt_at } : h.handled > 0 || !h.error ? { ...h.lease, at: h.acked_at } : [];
@@ -2926,32 +2862,25 @@ var DrainController = class {
2926
2862
  _locked = false;
2927
2863
  _ratio = 0.5;
2928
2864
  /**
2929
- * Per-stream re-visit schedule (#1090): `stream → next visit` (ms since
2930
- * epoch). Holds both retry backoff (`HandleResult.next_attempt_at`) and the
2931
- * `defer` outcome; cleared on successful ack or terminal block. Lives in
2932
- * process memory — per-worker pacing by design (see {@link BackoffOptions}
2933
- * for the multi-worker trade-off). Its wake re-arms drain at the earliest
2934
- * pending visit.
2865
+ * Local wake for streams this worker parked (backoff or defer). The
2866
+ * schedule itself is persisted in the store; this only re-arms the drain
2867
+ * at the earliest pending visit.
2935
2868
  */
2936
2869
  _defer = new DeferTimer(() => {
2937
2870
  this._armed = true;
2938
2871
  });
2939
- /** Worker timer (ACT-1103). Set when `start()` is active, undefined otherwise. */
2872
+ /** Worker timer. Set when `start()` is active, undefined otherwise. */
2940
2873
  _worker;
2941
2874
  /**
2942
- * Misroutings this controller has reported (#1563). A resolver returning a
2875
+ * Misroutings this controller has reported. A resolver returning a
2943
2876
  * projection's target does so for every matching event; one line per event
2944
2877
  * would bury the signal it exists to raise.
2945
2878
  */
2946
2879
  _misrouted = /* @__PURE__ */ new Set();
2947
2880
  _stopped = false;
2948
2881
  /**
2949
- * Resolves when the cycle currently in flight finishes; `undefined` when
2950
- * no cycle is running (#1442). `_locked` answers "is a cycle running?" for
2951
- * the overlap guard; this answers "tell me when it is done" for a graceful
2952
- * shutdown, which needs to await the handler rather than abandon it
2953
- * mid-`await` with the stream still leased. Never rejects — `drain()`
2954
- * contains its own errors — so awaiting it is always safe.
2882
+ * Resolves when the cycle in flight finishes, so a graceful shutdown can
2883
+ * wait for it. Never rejects.
2955
2884
  */
2956
2885
  _inflight;
2957
2886
  _inflight_done;
@@ -2968,16 +2897,9 @@ var DrainController = class {
2968
2897
  this._armed = true;
2969
2898
  }
2970
2899
  /**
2971
- * Re-seed a persisted defer schedule into the process-local timer at cold
2972
- * start (#1221). The `_defer` map lives in worker memory and is empty
2973
- * after a restart; a stream deferred to a future due-time (e.g. an idle
2974
- * autoclose aggregate) is durable in the store's `deferred_at` but has
2975
- * nothing in memory to re-arm the drain at the due-time. The orchestrator
2976
- * reads the persisted `deferred_at` for this controller's lane and calls
2977
- * this to park the stream + (re)schedule the shared wake — so the drain
2978
- * re-arms at the due-time with no intervening commit. `schedule()`
2979
- * collapses many seeds into one timer, so callers may seed in a loop and
2980
- * let the earliest due-time win.
2900
+ * Re-seed a persisted `deferred_at` into the local wake at cold start, so
2901
+ * an idle deferred stream re-arms at its due-time with no new commit.
2902
+ * Seeds collapse into one timer; the earliest wins.
2981
2903
  */
2982
2904
  seed_defer(stream, at) {
2983
2905
  this._defer.set(stream, at);
@@ -2987,31 +2909,21 @@ var DrainController = class {
2987
2909
  get armed() {
2988
2910
  return this._armed;
2989
2911
  }
2990
- /**
2991
- * The cycle currently in flight, or `undefined` when idle (#1442). A
2992
- * graceful shutdown awaits this so an in-flight handler reaches its `ack`
2993
- * — which releases the stream's lease — instead of being abandoned with
2994
- * the lease held until it expires.
2995
- */
2912
+ /** The cycle in flight, or `undefined` when idle. */
2996
2913
  get inflight() {
2997
2914
  return this._inflight;
2998
2915
  }
2999
- /**
3000
- * This lane's configured lease budget, or `undefined` when the lane didn't
3001
- * pin one. It is the operator's own statement of how long a handler may
3002
- * legitimately hold a stream, which makes it the right basis for a
3003
- * shutdown grace budget (#1442).
3004
- */
2916
+ /** This lane's configured lease, or `undefined`; the shutdown grace basis. */
3005
2917
  get lease_millis() {
3006
2918
  return this._deps.defaults?.leaseMillis;
3007
2919
  }
3008
- /** Lane this controller drains (undefined = legacy single-lane span). */
2920
+ /** Lane this controller drains (undefined spans all lanes). */
3009
2921
  get lane() {
3010
2922
  return this._deps.lane;
3011
2923
  }
3012
2924
  /**
3013
2925
  * Start a per-lane worker that drains at the lane's `cycleMs`
3014
- * cadence (ACT-1103). When armed, the worker calls `drain()` on every
2926
+ * cadence. When armed, the worker calls `drain()` on every
3015
2927
  * tick and re-schedules; when not armed, it still re-schedules at
3016
2928
  * `cycleMs` so a future `arm()` is picked up on the next tick.
3017
2929
  *
@@ -3056,21 +2968,14 @@ var DrainController = class {
3056
2968
  });
3057
2969
  const lagging = Math.ceil(streamLimit * this._ratio);
3058
2970
  const leading = streamLimit - lagging;
3059
- const cycle = await run_drain_cycle(
3060
- this._deps.ops,
3061
- this._deps.registry,
3062
- this._deps.batch_handlers,
3063
- this._misrouted,
3064
- this._deps.breaker.failing,
3065
- this._deps.handle,
3066
- this._deps.handle_batch,
2971
+ const cycle = await run_drain_cycle(this._deps, {
3067
2972
  lagging,
3068
2973
  leading,
3069
2974
  eventLimit,
3070
2975
  leaseMillis,
3071
- (b) => this._deps.on_blocked(b),
3072
- this._deps.lane
3073
- );
2976
+ misrouted: this._misrouted,
2977
+ store_failing: this._deps.breaker.failing
2978
+ });
3074
2979
  if (!cycle) {
3075
2980
  this._deps.breaker.passed();
3076
2981
  this._armed = false;
@@ -3198,26 +3103,13 @@ var SettleLoop = class {
3198
3103
  _timer = void 0;
3199
3104
  _running = false;
3200
3105
  /**
3201
- * Resolves when the cycle currently in flight finishes; `undefined` when
3202
- * idle (#1468). `_running` answers "is a cycle running?" for the
3203
- * re-arm bookkeeping; this answers "tell me when it is done" for a
3204
- * graceful shutdown.
3205
- *
3206
- * `stop()` only cancels *scheduling* — a cycle already inside its
3207
- * correlate → drain loop keeps going, and because `DrainController.drain`
3208
- * does not consult `_stopped`, it can claim a stream after teardown
3209
- * returned and after the store adapter was disposed. Never rejects: the
3210
- * cycle's own `catch` contains its errors, so awaiting this is safe.
3106
+ * Resolves when the cycle in flight finishes, so shutdown can wait for
3107
+ * it (`stop()` cancels scheduling only). Never rejects.
3211
3108
  */
3212
3109
  _inflight;
3213
3110
  /**
3214
- * Set when a `schedule()` timer fires while a cycle is still running
3215
- * (ACT-1205). The in-flight cycle's `finally` re-arms one more pass so
3216
- * the wake-up isn't dropped — a commit landing during the final
3217
- * no-progress drain pass would otherwise leave armed controllers with
3218
- * nothing to re-drain on an instance with no lane `cycleMs` and no
3219
- * polling. Carries the options of the dropped call so the re-armed
3220
- * pass honors its `debounceMs`/`maxPasses`/drain overrides.
3111
+ * A wake-up that fired while a cycle was running. The running cycle's
3112
+ * `finally` schedules one more pass with these options, so it isn't lost.
3221
3113
  */
3222
3114
  _pending = void 0;
3223
3115
  _deps;
@@ -3289,7 +3181,7 @@ var SettleLoop = class {
3289
3181
  }, debounceMs);
3290
3182
  }
3291
3183
  /**
3292
- * The cycle currently in flight, or `undefined` when idle (#1468). A
3184
+ * The cycle currently in flight, or `undefined` when idle. A
3293
3185
  * graceful shutdown awaits this alongside the drain controllers so a
3294
3186
  * settle parked in `correlate` does not resume after teardown.
3295
3187
  */
@@ -3435,17 +3327,17 @@ function validate_only_lanes(options, lanes) {
3435
3327
  }
3436
3328
  var Act = class {
3437
3329
  _emitter = new EventEmitter();
3438
- /** ACT-984: orchestrator-owned circuit breaker shared by all drain lanes. */
3330
+ /** Circuit breaker shared by all drain lanes. */
3439
3331
  _breaker;
3440
- /** #803: gate the `Store.notify` subscription side. */
3332
+ /** Whether this instance subscribes to `Store.notify`. */
3441
3333
  _listen;
3442
- /** #803: gate the local reaction pipeline (drain controllers, settle, correlate). */
3334
+ /** Whether this instance runs reactions (drain, settle, correlate). */
3443
3335
  _drain;
3444
3336
  /** Event names with at least one registered reaction (computed at build time) */
3445
3337
  _reactive_events;
3446
3338
  /** One DrainController per active lane, keyed by lane name. */
3447
3339
  _drain_controllers;
3448
- /** Correlation state machine: lazy init, dynamic-resolver scan, periodic worker. */
3340
+ /** Correlation: lazy init and the scan that marks work. */
3449
3341
  _correlate;
3450
3342
  /** Debounced correlate→drain catch-up loop. */
3451
3343
  _settle;
@@ -3475,26 +3367,10 @@ var Act = class {
3475
3367
  * Emit a lifecycle event. The payload type is inferred from the event name
3476
3368
  * via {@link ActLifecycleEvents}.
3477
3369
  *
3478
- * **Every listener is contained individually.** Lifecycle listeners are
3479
- * observers — `observability.md` promises that a throwing one is "contained,
3480
- * not fatal" — and containment belongs here rather than at each call site,
3481
- * for two reasons the previous arrangement got wrong (#1437):
3482
- *
3483
- * - Wrapping the *emit* rather than each *listener* still let the first
3484
- * thrower abort the rest: `EventEmitter.emit` stops dispatching on the
3485
- * first exception, so a second `app.on("acked", …)` never ran. The
3486
- * documented "the remaining sinks still fire" was false whenever an event
3487
- * had more than one listener. Same lesson as #1423, where guarding the
3488
- * loop instead of each callback left every later SSE subscriber unserved.
3489
- * - Only *some* call sites wrapped at all. The drain contained `acked` and
3490
- * `blocked`; `committed`, `forgotten` and `close()`'s `closed` did not, so
3491
- * a throwing listener rejected `do()`, `forget()` and `close()` **after**
3492
- * their durable work had already landed. A caller retrying a "failed"
3493
- * `do()` writes the event twice, since the framework has no dedup by
3494
- * design.
3495
- *
3496
- * Containing here makes it a property of emitting, so a new lifecycle event
3497
- * cannot reintroduce the gap by omission.
3370
+ * Each listener is contained on its own: a throwing listener is logged,
3371
+ * the remaining listeners still run, and the caller (`do()`, `forget()`,
3372
+ * `close()`, the drain) never sees the throw, since its durable work has
3373
+ * already landed.
3498
3374
  *
3499
3375
  * Uses `rawListeners` so `once` wrappers still de-register themselves, and
3500
3376
  * returns "had listeners" to preserve the `EventEmitter.emit` contract.
@@ -3555,29 +3431,23 @@ var Act = class {
3555
3431
  */
3556
3432
  _event_to_state;
3557
3433
  /**
3558
- * Event-name → lane fan-in for selective arming (ACT-1103). Built by
3434
+ * Event-name → lane fan-in for selective arming. Built by
3559
3435
  * `classify_registry` once per build. `"all"` means at least one of
3560
3436
  * the event's reactions is a dynamic resolver (lane opaque until
3561
3437
  * runtime); a `Set<string>` lists the static lanes only that event's
3562
3438
  * reactions target.
3563
3439
  */
3564
3440
  _event_to_lanes;
3565
- /**
3566
- * Audit dependency bag (#723). Built once at construction; held as
3567
- * an immutable snapshot of the registry state the audit module
3568
- * needs. Lives in `internal/audit.ts` — this orchestrator never
3569
- * carries audit logic, only the deps + a one-liner that hands them
3570
- * over.
3571
- */
3441
+ /** What `internal/audit.ts` needs, built once at construction. */
3572
3442
  _audit_deps;
3573
3443
  /** Logger resolved at construction time (after user port configuration) */
3574
3444
  _logger = log();
3575
- /** Wraps a public-method body so internal `store()`/`cache()` resolve to the
3576
- * per-Act ports (ACT-501). No-op when the Act is unscoped — so the singleton
3577
- * path keeps reading fresh `store()`/`cache()` per call, which matters for
3578
- * tests that dispose and re-seed mid-suite. */
3579
3445
  /** This Act's ports: its own bag, or the singleton adapters. */
3580
3446
  _ports;
3447
+ /**
3448
+ * Runs a body inside this Act's ports frame, so internal
3449
+ * `store()`/`cache()` calls resolve to `_ports`.
3450
+ */
3581
3451
  _scoped;
3582
3452
  /**
3583
3453
  * Correlation-id generator for originating actions. Bound at
@@ -3596,24 +3466,18 @@ var Act = class {
3596
3466
  /** Reaction dispatchers built once and handed to run_drain_cycle each cycle. */
3597
3467
  _handle;
3598
3468
  _handle_batch;
3599
- /** Declared drain lanes (ACT-1103). */
3469
+ /** Declared drain lanes. */
3600
3470
  _lanes;
3601
3471
  /**
3602
- * Per-stream close serialization tails (#1222). Chains each stream's
3603
- * windowed-close work behind the previous one so a manual
3604
- * `app.close([{stream, before}])` and an autoclose windowed close for
3605
- * the same stream never run their guard-free prune concurrently — the
3606
- * manual path bypasses the `__autoclose__:X` drain lease that would
3607
- * otherwise exclude them, so without this both closers archive the
3608
- * same prefix. Process-local: both racers run on the same Act
3609
- * instance. Entries are dropped once their tail resolves so the map
3610
- * doesn't grow with distinct stream names.
3472
+ * Per-stream close serialization tails, so a manual close and an
3473
+ * autoclose of the same stream never prune concurrently (the manual path
3474
+ * has no drain lease to exclude it). Entries are dropped once settled.
3611
3475
  */
3612
3476
  _close_locks = /* @__PURE__ */ new Map();
3613
3477
  /**
3614
- * Run `work` under the per-stream close lock (#1222). Serializes close
3615
- * critical sections for the same stream (windowed prunes, and full closes
3616
- * since #1738) while letting different streams proceed in parallel.
3478
+ * Run `work` under the per-stream close lock. Serializes close
3479
+ * critical sections for the same stream (windowed prunes and full
3480
+ * closes) while letting different streams proceed in parallel.
3617
3481
  */
3618
3482
  _with_close_lock(stream, work) {
3619
3483
  const prev = this._close_locks.get(stream) ?? Promise.resolve();
@@ -3640,11 +3504,11 @@ var Act = class {
3640
3504
  * @param states Merged map of state name → state definition
3641
3505
  * @param batch_handlers Static-target projection batch handlers (target → handler)
3642
3506
  * @param options Tuning knobs — see {@link ActOptions}
3643
- * @param lanes Declared drain lanes (ACT-1103). The builder collects
3644
- * these from `.withLane(...)` calls. Slice 1 records them on the
3645
- * instance; later slices fan out one `DrainController` per lane.
3507
+ * @param lanes Declared drain lanes. The builder collects
3508
+ * these from `.withLane(...)` calls; one `DrainController` runs
3509
+ * per lane, plus the implicit `"default"`.
3646
3510
  * @param patch_fn The per-event patch step selected once by the builder
3647
- * from `ActOptions.validateFoldedState` (ACT-1238) — `bare_patch` by
3511
+ * from `ActOptions.validateFoldedState` — `bare_patch` by
3648
3512
  * default, `validating_patch` when the flag is on. The builder uses
3649
3513
  * the same value for its projection-fold handlers, so there is a
3650
3514
  * single selection site. Defaults to `bare_patch` for direct
@@ -3659,16 +3523,15 @@ var Act = class {
3659
3523
  this._ports = options.scoped ?? default_scope();
3660
3524
  const ports = this._ports;
3661
3525
  this._scoped = make_run_scoped({
3662
- // Delegating getters, NOT a spread: `default_scope()` resolves the
3663
- // process singletons lazily, so copying its properties would freeze
3664
- // whichever adapters happened to be installed at construction and
3665
- // ignore a later `store(...)` / `cache(...)`.
3526
+ // Getters, not a spread: the singletons resolve lazily, so a later
3527
+ // `store(...)` / `cache(...)` still takes effect.
3666
3528
  get store() {
3667
3529
  return ports.store;
3668
3530
  },
3669
3531
  get cache() {
3670
3532
  return ports.cache;
3671
3533
  },
3534
+ // Parsed per build, so a bad window throws on every build.
3672
3535
  autoclose_window: resolveAutocloseConfig(options).autocloseWindow
3673
3536
  });
3674
3537
  this._correlator = options.correlator ?? default_correlator;
@@ -3676,8 +3539,6 @@ var Act = class {
3676
3539
  this._cd = build_drain(this._logger);
3677
3540
  this._handle = build_handle({
3678
3541
  logger: this._logger,
3679
- // The orchestrator owns ambient context; `build_handle` only asks for
3680
- // the triggering event to be in scope while the handler runs.
3681
3542
  reaction_scope: make_reaction_scope({
3682
3543
  do: this._bound_do,
3683
3544
  load: this._bound_load,
@@ -3712,16 +3573,8 @@ var Act = class {
3712
3573
  resolveCircuitBreakerConfig(options.circuitBreaker),
3713
3574
  {
3714
3575
  on_error: (error, circuit) => this._emit_error(error, circuit),
3715
- // Re-probe the store when the cooldown elapses, so recovery is
3716
- // automatic even on the default lane (which has no periodic poller).
3717
- // The wake fires `settle()`, which (in half-open) runs a real store
3718
- // probe: for a dynamic-resolver app the probe is settle's correlate
3719
- // (a store scan); for a static-reaction app correlate is a no-op that
3720
- // records no health, so the probe is settle's DRAIN claim — either
3721
- // way one success closes the breaker and every loop resumes, a
3722
- // failure re-opens it and reschedules the wake. Settle does NOT close
3723
- // the breaker off a no-op correlate (#1329) — only a real store op
3724
- // (correlate scan or drain claim) records `passed()`.
3576
+ // When the cooldown elapses, settle once: its scan or claim is the
3577
+ // half-open probe that closes or re-opens the breaker.
3725
3578
  on_retry: () => {
3726
3579
  this.settle({ debounceMs: 0 });
3727
3580
  }
@@ -3729,12 +3582,9 @@ var Act = class {
3729
3582
  );
3730
3583
  }
3731
3584
  /**
3732
- * One DrainController per active lane. The implicit "default" lane is
3733
- * always present unless onlyLanes excludes it. Each controller filters
3734
- * its claim() by its lane name; the legacy single-controller path is the
3735
- * no-lane-declared case with `lane: undefined` deps so claim() doesn't
3736
- * filter (preserves the single-lane SQL planner shape for apps that never
3737
- * call withLane).
3585
+ * One DrainController per active lane, plus the implicit "default" unless
3586
+ * `onlyLanes` excludes it. Apps that declare no lanes pass no lane filter
3587
+ * to `claim`.
3738
3588
  */
3739
3589
  _build_drain_controllers(options, lanes) {
3740
3590
  const all_lanes = ["default", ...lanes.map((l) => l.name)];
@@ -3753,11 +3603,7 @@ var Act = class {
3753
3603
  handle_batch: this._handle_batch,
3754
3604
  on_acked: (acked) => this.emit("acked", acked),
3755
3605
  on_blocked: (blocked) => this.emit("blocked", blocked),
3756
- // Reaction-requested close. Runs the same close machinery as
3757
- // `app.close` (tombstone guard + archive + atomic truncate) for the
3758
- // targets a handler signalled via `CloseSignal`. No `correlate()`
3759
- // here — the drain that produced these targets has already
3760
- // correlated.
3606
+ // Reaction-requested close: the same machinery as `app.close`.
3761
3607
  on_close: async (targets) => {
3762
3608
  const close_actor = { id: "$close", name: "close" };
3763
3609
  const result = await run_close_cycle(targets, {
@@ -3774,12 +3620,7 @@ var Act = class {
3774
3620
  this.emit("closed", result);
3775
3621
  },
3776
3622
  breaker: this._breaker,
3777
- // Re-scope the per-lane worker's auto-start ticks so their drain
3778
- // resolves the scoped ports, not the singleton (#1191).
3779
3623
  run_scoped: this._scoped,
3780
- // Pass lane only when a true per-lane controller is active.
3781
- // The all-lanes (single default) case keeps lane=undefined so
3782
- // adapter SQL collapses to the single-lane shape.
3783
3624
  lane: single_default_lane ? void 0 : name,
3784
3625
  defaults: cfg && {
3785
3626
  streamLimit: cfg.streamLimit,
@@ -3793,17 +3634,9 @@ var Act = class {
3793
3634
  return controllers;
3794
3635
  }
3795
3636
  /**
3796
- * Orphaned-lane startup advisory (#1220). When `onlyLanes` is set, this
3797
- * instance builds a controller only for its slice of the declared lane
3798
- * universe — every OTHER declared lane's stream is persisted (correlate
3799
- * subscribes all static targets regardless of `onlyLanes`) but never
3800
- * claimed here. If no peer worker deploys with those lanes in ITS
3801
- * `onlyLanes`, their reactions accumulate forever, silently. A single
3802
- * process can't verify the cluster invariant `∪ onlyLanes ⊇ declared
3803
- * lanes`, so we surface the per-instance signal — "these declared lanes
3804
- * have no controller here" — the same way the deprecated-event advisory
3805
- * surfaces legacy events. No advisory when `onlyLanes` is unset (every
3806
- * lane gets a controller) or covers every declared lane.
3637
+ * Startup advisory naming declared lanes that `onlyLanes` leaves without a
3638
+ * controller here. One process can't check that the cluster covers every
3639
+ * lane, so it reports its own gaps.
3807
3640
  */
3808
3641
  _advise_orphaned_lanes(options, lanes) {
3809
3642
  if (!options.onlyLanes || options.onlyLanes.length === 0) return;
@@ -3817,25 +3650,15 @@ var Act = class {
3817
3650
  `Act declared ${orphaned.length} orphaned lane(s) on this instance: ${list}. onlyLanes excludes them, so no DrainController claims their streams here \u2014 their reactions accumulate un-drained unless a peer worker deploys with these lanes in its onlyLanes. Ensure the cluster invariant holds: the union of every worker's onlyLanes must cover every declared lane. See docs/docs/guides/production-checklist.md \xA7 Sizing lanes.`
3818
3651
  );
3819
3652
  }
3820
- /**
3821
- * Audit deps bag. Snapshotted after registry classification and
3822
- * drain-controller build so the audit module sees the finalized lane
3823
- * set. Held as an immutable bag — the orchestrator never carries audit
3824
- * logic itself, only this typed contract.
3825
- */
3653
+ /** Audit deps, built after the controllers so the lane set is final. */
3826
3654
  _build_audit_deps() {
3827
3655
  return {
3828
3656
  store,
3829
3657
  logger: this._logger,
3830
3658
  event_to_state: this._event_to_state,
3831
3659
  states: this._states,
3832
- // The DECLARED lane universe — the implicit "default" plus every
3833
- // `.withLane(...)` name — NOT `_drain_controllers.keys()` (#1224).
3834
- // An `onlyLanes`-filtered instance builds a controller only for its
3835
- // slice of lanes, so keying off the active controller set would flag
3836
- // a stream correctly assigned to an excluded-but-declared lane (one
3837
- // another worker drains) as `unknown-lane`. The audit reports what's
3838
- // structurally routable across the cluster, not what this process runs.
3660
+ // Declared lanes, not this process's controllers: a lane another
3661
+ // worker drains is not `unknown-lane`.
3839
3662
  declared_lanes: /* @__PURE__ */ new Set(["default", ...this._lanes.map((l) => l.name)]),
3840
3663
  routed_events: new Set(this._event_to_lanes.keys())
3841
3664
  };
@@ -3851,10 +3674,8 @@ var Act = class {
3851
3674
  static_targets: classification.static_targets,
3852
3675
  cd: this._cd,
3853
3676
  max_subscribed_streams: options.maxSubscribedStreams ?? DEFAULT_MAX_SUBSCRIBED_STREAMS,
3854
- // Every lane a controller can exist for, so correlate can reroute a
3855
- // dynamic resolution that names one that doesn't (#1564). Declared,
3856
- // not active: `onlyLanes` shrinks this process's controllers, but a
3857
- // lane another process claims is still a valid destination.
3677
+ // Declared lanes (not active ones): a lane another process claims is
3678
+ // still a valid destination.
3858
3679
  declared_lanes: /* @__PURE__ */ new Set([
3859
3680
  "default",
3860
3681
  ...this._lanes.map((l) => l.name)
@@ -3862,26 +3683,14 @@ var Act = class {
3862
3683
  on_init: () => {
3863
3684
  if (this._drain && this._reactive_events.size > 0) this._arm_all();
3864
3685
  },
3865
- // Cold-start defer re-seed (#1221). Skipped on writer-only instances
3866
- // (`drain: false`) — they run no local controllers to re-arm.
3867
3686
  on_init_async: this._drain ? () => this._seed_persisted_defers() : void 0
3868
3687
  });
3869
3688
  }
3870
3689
  /**
3871
- * Re-seed every active lane controller's process-local defer timer from
3872
- * the store's persisted `deferred_at` (#1221). Runs once at cold start,
3873
- * inside `CorrelateCycle.init`, after static targets are subscribed.
3874
- *
3875
- * The defer timer is worker memory: empty after a restart. A stream
3876
- * deferred to a future due-time (the classic case: an idle autoclose
3877
- * aggregate that deferred its terminal close) is durable in the store but
3878
- * has nothing in memory to re-arm the drain — the controller disarms on
3879
- * the first empty claim and, since the aggregate is idle, no commit ever
3880
- * re-arms it. Reading the persisted schedule and seeding the owning lane's
3881
- * timer restores the wake, so the close fires at the due-time.
3882
- *
3883
- * Streams whose lane has no controller on this instance (excluded by
3884
- * `onlyLanes`) are skipped — a peer worker owns that lane's timer.
3690
+ * At cold start, re-seed each lane controller's local wake from the
3691
+ * persisted future `deferred_at`, so an idle deferred stream (an
3692
+ * autoclose waiting out its window) still fires on time. Streams on lanes
3693
+ * this instance doesn't run are skipped.
3885
3694
  */
3886
3695
  async _seed_persisted_defers() {
3887
3696
  const now = Date.now();
@@ -3895,10 +3704,6 @@ var Act = class {
3895
3704
  _build_settle(options) {
3896
3705
  return new SettleLoop(
3897
3706
  {
3898
- // Scope the init like every other store-touching path — a bare
3899
- // `this._correlate.init()` runs `store().subscribe(...)` against
3900
- // the singleton for a scoped Act, so static targets never land on
3901
- // the scoped store and `_initialized` then blocks a retry (#1191).
3902
3707
  init: () => this._scoped(() => this._correlate.init()),
3903
3708
  checkpoint: () => this._correlate.checkpoint,
3904
3709
  correlate: (q) => this._correlate_scanned(q, true),
@@ -3916,19 +3721,11 @@ var Act = class {
3916
3721
  * already in flight a bounded chance to finish, then remove lifecycle
3917
3722
  * listeners and tear down the cross-process notify subscription.
3918
3723
  *
3919
- * The order is deliberate (#1442). Scheduling stops first, so nothing new
3920
- * is claimed while teardown runs. Then in-flight cycles are awaited up to
3921
- * `graceMs`: a reaction handler parked on an `await` holds its stream's
3922
- * lease until it acks, so abandoning it costs the replacement worker up to
3923
- * `leaseMillis` of dead time on that stream and discards the round of work
3924
- * (which #1418 then redelivers). Listeners come off *after* that wait, not
3925
- * before, so an `acked` / `blocked` subscriber still observes the work
3926
- * that completed during the grace window.
3927
- *
3928
- * The budget is a ceiling, not a delay — teardown continues the moment the
3929
- * last in-flight cycle finishes. When it is exhausted, teardown proceeds
3930
- * anyway: one stuck handler must not hang a deploy, which is the failure
3931
- * mode an unbounded wait would trade for.
3724
+ * Scheduling stops first, then in-flight cycles get up to `graceMs` to
3725
+ * reach their `ack` (an abandoned handler holds its lease until it
3726
+ * expires). Listeners come off after the wait, so they still see work that
3727
+ * finished during it. The budget is a ceiling, not a delay; when it runs
3728
+ * out, teardown proceeds anyway.
3932
3729
  *
3933
3730
  * Idempotent — repeated calls return the same promise, and the first
3934
3731
  * call's `graceMs` is the one that applies. Registered automatically with
@@ -3961,26 +3758,10 @@ var Act = class {
3961
3758
  * whichever comes first. Cycle promises never reject (`drain()` contains
3962
3759
  * its own errors), so this never throws.
3963
3760
  *
3964
- * An omitted budget is derived from the lanes that actually have a cycle
3965
- * in flight: their `leaseMillis` is the operator's own statement of how
3966
- * long one of their handlers may hold a stream, which makes it the honest
3967
- * ceiling for how long teardown should wait for that handler. A parked
3968
- * lane that pinned no lease contributes `drain()`'s own fallback, and the
3969
- * whole thing is capped so a long-leased lane cannot hold a deploy open.
3970
- * Idle lanes do not count — nothing is running on them to wait for.
3971
- *
3972
- * An in-flight settle counts the same way, on the same fallback (#1617).
3973
- * It is waited on like any cycle, and deriving from the lanes alone gave
3974
- * it a budget of `0` whenever it was the only thing running — which
3975
- * returned before the wait it was about to be added to.
3976
- *
3977
- * A lane configured `leaseMillis: 0` takes the fallback rather than its
3978
- * own value, which is why this coalesces on falsy and not just on absent
3979
- * (#1647). A zero-length lease expires the instant it is granted, so it
3980
- * has no answer to offer for "how long may a handler hold this stream" —
3981
- * it is the pinned-no-lease case spelled with a number, and #1617 already
3982
- * settled what that case is worth. Taking it literally derived a budget
3983
- * of `0` and abandoned the very cycle this had just found running.
3761
+ * An omitted budget is the largest `leaseMillis` among lanes with a cycle
3762
+ * in flight (the drain's fallback for lanes that pinned none, or pinned
3763
+ * 0, which is the same as none), with an in-flight settle counting on the
3764
+ * fallback, capped at the maximum. Idle lanes don't count.
3984
3765
  */
3985
3766
  _derive_grace_ms(running, settling) {
3986
3767
  let max = settling ? DEFAULT_SHUTDOWN_GRACE_MS : 0;
@@ -4253,7 +4034,7 @@ var Act = class {
4253
4034
  }
4254
4035
  /**
4255
4036
  * Wipe the sensitive-data payload for every event on the stream — see
4256
- * {@link IAct.forget}. Application-level half of #566.
4037
+ * {@link IAct.forget}.
4257
4038
  *
4258
4039
  * Throws on adapters without `Store.forget_pii`, invalidates the cache
4259
4040
  * entry for the stream, emits the `forgotten` lifecycle event with the
@@ -4294,7 +4075,7 @@ var Act = class {
4294
4075
  *
4295
4076
  * Call `correlate()` before `drain()`. It is not only how dynamic targets
4296
4077
  * are discovered: a stream is claimable while `at < correlated_at`, and
4297
- * `correlate` is the only component that raises that mark (#1487), so a
4078
+ * `correlate` is the only component that raises that mark, so a
4298
4079
  * commit no correlate has seen is not drainable — including for static
4299
4080
  * targets, which were served by a probe of the event log before. For a
4300
4081
  * higher-level API that handles debouncing, correlation, and signaling
@@ -4327,14 +4108,14 @@ var Act = class {
4327
4108
  return { fetched: [], leased: [], acked: [], blocked: [] };
4328
4109
  return this._scoped(() => this._drain_all(options));
4329
4110
  }
4330
- /** Arm every active lane controller (ACT-1103). */
4111
+ /** Arm every active lane controller. */
4331
4112
  _arm_all() {
4332
4113
  this._correlate.arm();
4333
4114
  for (const c of this._drain_controllers.values()) c.arm();
4334
4115
  }
4335
4116
  /**
4336
4117
  * Arm only the lane controllers whose reactions match the supplied
4337
- * event names (ACT-1103 selective arming). Events with any dynamic
4118
+ * event names (selective arming). Events with any dynamic
4338
4119
  * resolver fall back to `_arm_all()` via the `"all"` sentinel — the
4339
4120
  * resolver's lane isn't known until correlate runs the function.
4340
4121
  * Events with no reactions are skipped; `_event_to_lanes` doesn't
@@ -4438,7 +4219,7 @@ var Act = class {
4438
4219
  return { subscribed, last_id };
4439
4220
  }
4440
4221
  /**
4441
- * `correlate` plus whether the pass actually read the store (#1510).
4222
+ * `correlate` plus whether the pass actually read the store.
4442
4223
  *
4443
4224
  * The settle loop needs that extra bit to decide whether the pass carries a
4444
4225
  * circuit-breaker health signal, and a disarmed pass carries none. It stays
@@ -4699,7 +4480,7 @@ var Act = class {
4699
4480
  });
4700
4481
  }
4701
4482
  /**
4702
- * Operator-driven store audit (#723).
4483
+ * Operator-driven store audit.
4703
4484
  *
4704
4485
  * Walks the connected store and yields per-category findings —
4705
4486
  * each tagged with the remediation it suggests. Same operator-
@@ -4751,7 +4532,7 @@ var Act = class {
4751
4532
  * Bulk-update scheduling priority for streams matching `filter`.
4752
4533
  *
4753
4534
  * Operator-grade override of the `claim()` lagging-frontier
4754
- * ordering (ACT-102). Useful when a long-running replay needs to
4535
+ * ordering. Useful when a long-running replay needs to
4755
4536
  * jump ahead of other lagging streams, or when a no-longer-urgent
4756
4537
  * job should yield slots back to the rest. Build-time priorities
4757
4538
  * (set via the resolver's `priority` field) are subject to a
@@ -4848,12 +4629,12 @@ var Act = class {
4848
4629
  */
4849
4630
  /**
4850
4631
  * After a close, forget any target whose subscription row the truncate
4851
- * removed, so a later correlate can re-subscribe it (#1398). Restart
4632
+ * removed, so a later correlate can re-subscribe it. Restart
4852
4633
  * targets keep their row, so only fully-retired streams are forgotten.
4853
4634
  */
4854
4635
  /**
4855
4636
  * Advance correlation until the read cursor reaches `until`, and report
4856
- * where it landed (#1487). Used by the close cycle's safety probe, which
4637
+ * where it landed. Used by the close cycle's safety probe, which
4857
4638
  * cannot judge a subscription's pending work over events correlate has
4858
4639
  * not resolved yet.
4859
4640
  *
@@ -4879,13 +4660,12 @@ var Act = class {
4879
4660
  * A tombstone seed means the stream was retired; a snapshot seed means it
4880
4661
  * was restarted and is still consuming.
4881
4662
  *
4882
- * `truncate` no longer removes the subscription row (#1527), so this is no
4663
+ * `truncate` no longer removes the subscription row, so this is no
4883
4664
  * longer repairing damage the close itself did. It still matters, because
4884
4665
  * the row can disappear later: reclaiming retired subscriptions is an
4885
4666
  * operator job now, and that `DELETE` can land while this process is
4886
4667
  * running. Forgetting here keeps the in-process view from outliving a row
4887
- * an operator removed, which is the same silent-no-delivery failure #1398
4888
- * described — a reaction whose target is named after the stream would never
4668
+ * an operator removed, which is a silent-no-delivery failure — a reaction whose target is named after the stream would never
4889
4669
  * be re-registered.
4890
4670
  */
4891
4671
  _forget_closed_subscriptions(result) {
@@ -5160,7 +4940,7 @@ function reaction_on(event, events, builder) {
5160
4940
  const reaction = {
5161
4941
  handler: schedule ? make_deferred(handler, schedule) : handler,
5162
4942
  resolver: _this_,
5163
- // #1269: validate the whole bag at the declaration site so a bad
4943
+ // Validate the whole bag at the declaration site so a bad
5164
4944
  // `maxRetries`/`backoff`/`blockOnError` throws ZodError at build,
5165
4945
  // not a NaN gate on the first retry.
5166
4946
  options: resolveReactionConfig({
@@ -5362,7 +5142,7 @@ function act() {
5362
5142
  spec.flush,
5363
5143
  spec.config,
5364
5144
  patch_fn,
5365
- // Head loads strip sensitive keys like the warm path (#1320).
5145
+ // Head loads strip sensitive keys like the warm path.
5366
5146
  registry.sensitive_fields
5367
5147
  )
5368
5148
  )
@@ -5868,7 +5648,7 @@ var CsvFile = class {
5868
5648
  name: fields[1],
5869
5649
  // Revive dates like every Store adapter does — a Date in an event
5870
5650
  // payload must not depend on whether it came back through a store or
5871
- // through a CSV restore (#1399). The `created` column below has
5651
+ // through a CSV restore. The `created` column below has
5872
5652
  // always been parsed explicitly; the JSON columns were missed.
5873
5653
  data: JSON.parse(fields[2]),
5874
5654
  stream: fields[3],