@rotorsoft/act 1.32.13 → 1.32.15

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 (78) 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 +2 -12
  12. package/dist/@types/builders/event-builder.d.ts.map +1 -1
  13. package/dist/@types/builders/merge.d.ts +1 -1
  14. package/dist/@types/builders/reaction-builder.d.ts +1 -1
  15. package/dist/@types/builders/slice-builder.d.ts +2 -2
  16. package/dist/@types/builders/state-builder.d.ts +3 -4
  17. package/dist/@types/builders/state-builder.d.ts.map +1 -1
  18. package/dist/@types/csv.d.ts +1 -1
  19. package/dist/@types/disposers.d.ts.map +1 -1
  20. package/dist/@types/internal/audit.d.ts +12 -42
  21. package/dist/@types/internal/audit.d.ts.map +1 -1
  22. package/dist/@types/internal/autoclose-policy.d.ts +3 -3
  23. package/dist/@types/internal/autoclose-reaction.d.ts +2 -2
  24. package/dist/@types/internal/autoclose-window.d.ts +1 -1
  25. package/dist/@types/internal/close-cycle.d.ts +10 -39
  26. package/dist/@types/internal/close-cycle.d.ts.map +1 -1
  27. package/dist/@types/internal/close-signal.d.ts +3 -3
  28. package/dist/@types/internal/config.d.ts +3 -3
  29. package/dist/@types/internal/config.d.ts.map +1 -1
  30. package/dist/@types/internal/correlate-cycle.d.ts +39 -86
  31. package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
  32. package/dist/@types/internal/correlator.d.ts +1 -1
  33. package/dist/@types/internal/date-reviver.d.ts +1 -1
  34. package/dist/@types/internal/defer-config.d.ts +2 -2
  35. package/dist/@types/internal/defer-signal.d.ts +2 -2
  36. package/dist/@types/internal/defer-timer.d.ts +3 -3
  37. package/dist/@types/internal/drain-cycle.d.ts +35 -82
  38. package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
  39. package/dist/@types/internal/event-sourcing.d.ts +8 -19
  40. package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
  41. package/dist/@types/internal/event-versions.d.ts +1 -1
  42. package/dist/@types/internal/index.d.ts +5 -6
  43. package/dist/@types/internal/index.d.ts.map +1 -1
  44. package/dist/@types/internal/projection-fold.d.ts +2 -2
  45. package/dist/@types/internal/report-once.d.ts +3 -3
  46. package/dist/@types/internal/sensitive.d.ts +2 -28
  47. package/dist/@types/internal/sensitive.d.ts.map +1 -1
  48. package/dist/@types/internal/settle.d.ts +6 -19
  49. package/dist/@types/internal/settle.d.ts.map +1 -1
  50. package/dist/@types/internal/walk-streams.d.ts +0 -2
  51. package/dist/@types/internal/walk-streams.d.ts.map +1 -1
  52. package/dist/@types/ports.d.ts +3 -3
  53. package/dist/@types/scoped.d.ts +6 -16
  54. package/dist/@types/scoped.d.ts.map +1 -1
  55. package/dist/@types/types/action.d.ts +19 -19
  56. package/dist/@types/types/audit.d.ts +1 -1
  57. package/dist/@types/types/ports.d.ts +22 -26
  58. package/dist/@types/types/ports.d.ts.map +1 -1
  59. package/dist/@types/types/reaction.d.ts +8 -8
  60. package/dist/@types/types/registry.d.ts +1 -1
  61. package/dist/@types/types/schemas.d.ts +2 -2
  62. package/dist/@types/utils.d.ts +1 -1
  63. package/dist/{chunk-BI3UNNVA.js → chunk-JRTZGWVS.js} +1 -1
  64. package/dist/chunk-JRTZGWVS.js.map +1 -0
  65. package/dist/{chunk-FLAGQMWE.js → chunk-PZP5ZEZ4.js} +9 -9
  66. package/dist/chunk-PZP5ZEZ4.js.map +1 -0
  67. package/dist/index.cjs +137 -359
  68. package/dist/index.cjs.map +1 -1
  69. package/dist/index.js +132 -354
  70. package/dist/index.js.map +1 -1
  71. package/dist/test/index.cjs +7 -7
  72. package/dist/test/index.cjs.map +1 -1
  73. package/dist/test/index.js +2 -2
  74. package/dist/types/index.cjs.map +1 -1
  75. package/dist/types/index.js +1 -1
  76. package/package.json +1 -1
  77. package/dist/chunk-BI3UNNVA.js.map +0 -1
  78. package/dist/chunk-FLAGQMWE.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-FLAGQMWE.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-BI3UNNVA.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)
@@ -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) {
@@ -2926,32 +2853,25 @@ var DrainController = class {
2926
2853
  _locked = false;
2927
2854
  _ratio = 0.5;
2928
2855
  /**
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.
2856
+ * Local wake for streams this worker parked (backoff or defer). The
2857
+ * schedule itself is persisted in the store; this only re-arms the drain
2858
+ * at the earliest pending visit.
2935
2859
  */
2936
2860
  _defer = new DeferTimer(() => {
2937
2861
  this._armed = true;
2938
2862
  });
2939
- /** Worker timer (ACT-1103). Set when `start()` is active, undefined otherwise. */
2863
+ /** Worker timer. Set when `start()` is active, undefined otherwise. */
2940
2864
  _worker;
2941
2865
  /**
2942
- * Misroutings this controller has reported (#1563). A resolver returning a
2866
+ * Misroutings this controller has reported. A resolver returning a
2943
2867
  * projection's target does so for every matching event; one line per event
2944
2868
  * would bury the signal it exists to raise.
2945
2869
  */
2946
2870
  _misrouted = /* @__PURE__ */ new Set();
2947
2871
  _stopped = false;
2948
2872
  /**
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.
2873
+ * Resolves when the cycle in flight finishes, so a graceful shutdown can
2874
+ * wait for it. Never rejects.
2955
2875
  */
2956
2876
  _inflight;
2957
2877
  _inflight_done;
@@ -2968,16 +2888,9 @@ var DrainController = class {
2968
2888
  this._armed = true;
2969
2889
  }
2970
2890
  /**
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.
2891
+ * Re-seed a persisted `deferred_at` into the local wake at cold start, so
2892
+ * an idle deferred stream re-arms at its due-time with no new commit.
2893
+ * Seeds collapse into one timer; the earliest wins.
2981
2894
  */
2982
2895
  seed_defer(stream, at) {
2983
2896
  this._defer.set(stream, at);
@@ -2987,31 +2900,21 @@ var DrainController = class {
2987
2900
  get armed() {
2988
2901
  return this._armed;
2989
2902
  }
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
- */
2903
+ /** The cycle in flight, or `undefined` when idle. */
2996
2904
  get inflight() {
2997
2905
  return this._inflight;
2998
2906
  }
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
- */
2907
+ /** This lane's configured lease, or `undefined`; the shutdown grace basis. */
3005
2908
  get lease_millis() {
3006
2909
  return this._deps.defaults?.leaseMillis;
3007
2910
  }
3008
- /** Lane this controller drains (undefined = legacy single-lane span). */
2911
+ /** Lane this controller drains (undefined spans all lanes). */
3009
2912
  get lane() {
3010
2913
  return this._deps.lane;
3011
2914
  }
3012
2915
  /**
3013
2916
  * Start a per-lane worker that drains at the lane's `cycleMs`
3014
- * cadence (ACT-1103). When armed, the worker calls `drain()` on every
2917
+ * cadence. When armed, the worker calls `drain()` on every
3015
2918
  * tick and re-schedules; when not armed, it still re-schedules at
3016
2919
  * `cycleMs` so a future `arm()` is picked up on the next tick.
3017
2920
  *
@@ -3198,26 +3101,13 @@ var SettleLoop = class {
3198
3101
  _timer = void 0;
3199
3102
  _running = false;
3200
3103
  /**
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.
3104
+ * Resolves when the cycle in flight finishes, so shutdown can wait for
3105
+ * it (`stop()` cancels scheduling only). Never rejects.
3211
3106
  */
3212
3107
  _inflight;
3213
3108
  /**
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.
3109
+ * A wake-up that fired while a cycle was running. The running cycle's
3110
+ * `finally` schedules one more pass with these options, so it isn't lost.
3221
3111
  */
3222
3112
  _pending = void 0;
3223
3113
  _deps;
@@ -3289,7 +3179,7 @@ var SettleLoop = class {
3289
3179
  }, debounceMs);
3290
3180
  }
3291
3181
  /**
3292
- * The cycle currently in flight, or `undefined` when idle (#1468). A
3182
+ * The cycle currently in flight, or `undefined` when idle. A
3293
3183
  * graceful shutdown awaits this alongside the drain controllers so a
3294
3184
  * settle parked in `correlate` does not resume after teardown.
3295
3185
  */
@@ -3435,17 +3325,17 @@ function validate_only_lanes(options, lanes) {
3435
3325
  }
3436
3326
  var Act = class {
3437
3327
  _emitter = new EventEmitter();
3438
- /** ACT-984: orchestrator-owned circuit breaker shared by all drain lanes. */
3328
+ /** Circuit breaker shared by all drain lanes. */
3439
3329
  _breaker;
3440
- /** #803: gate the `Store.notify` subscription side. */
3330
+ /** Whether this instance subscribes to `Store.notify`. */
3441
3331
  _listen;
3442
- /** #803: gate the local reaction pipeline (drain controllers, settle, correlate). */
3332
+ /** Whether this instance runs reactions (drain, settle, correlate). */
3443
3333
  _drain;
3444
3334
  /** Event names with at least one registered reaction (computed at build time) */
3445
3335
  _reactive_events;
3446
3336
  /** One DrainController per active lane, keyed by lane name. */
3447
3337
  _drain_controllers;
3448
- /** Correlation state machine: lazy init, dynamic-resolver scan, periodic worker. */
3338
+ /** Correlation: lazy init and the scan that marks work. */
3449
3339
  _correlate;
3450
3340
  /** Debounced correlate→drain catch-up loop. */
3451
3341
  _settle;
@@ -3475,26 +3365,10 @@ var Act = class {
3475
3365
  * Emit a lifecycle event. The payload type is inferred from the event name
3476
3366
  * via {@link ActLifecycleEvents}.
3477
3367
  *
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.
3368
+ * Each listener is contained on its own: a throwing listener is logged,
3369
+ * the remaining listeners still run, and the caller (`do()`, `forget()`,
3370
+ * `close()`, the drain) never sees the throw, since its durable work has
3371
+ * already landed.
3498
3372
  *
3499
3373
  * Uses `rawListeners` so `once` wrappers still de-register themselves, and
3500
3374
  * returns "had listeners" to preserve the `EventEmitter.emit` contract.
@@ -3555,29 +3429,23 @@ var Act = class {
3555
3429
  */
3556
3430
  _event_to_state;
3557
3431
  /**
3558
- * Event-name → lane fan-in for selective arming (ACT-1103). Built by
3432
+ * Event-name → lane fan-in for selective arming. Built by
3559
3433
  * `classify_registry` once per build. `"all"` means at least one of
3560
3434
  * the event's reactions is a dynamic resolver (lane opaque until
3561
3435
  * runtime); a `Set<string>` lists the static lanes only that event's
3562
3436
  * reactions target.
3563
3437
  */
3564
3438
  _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
- */
3439
+ /** What `internal/audit.ts` needs, built once at construction. */
3572
3440
  _audit_deps;
3573
3441
  /** Logger resolved at construction time (after user port configuration) */
3574
3442
  _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
3443
  /** This Act's ports: its own bag, or the singleton adapters. */
3580
3444
  _ports;
3445
+ /**
3446
+ * Runs a body inside this Act's ports frame, so internal
3447
+ * `store()`/`cache()` calls resolve to `_ports`.
3448
+ */
3581
3449
  _scoped;
3582
3450
  /**
3583
3451
  * Correlation-id generator for originating actions. Bound at
@@ -3596,24 +3464,18 @@ var Act = class {
3596
3464
  /** Reaction dispatchers built once and handed to run_drain_cycle each cycle. */
3597
3465
  _handle;
3598
3466
  _handle_batch;
3599
- /** Declared drain lanes (ACT-1103). */
3467
+ /** Declared drain lanes. */
3600
3468
  _lanes;
3601
3469
  /**
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.
3470
+ * Per-stream close serialization tails, so a manual close and an
3471
+ * autoclose of the same stream never prune concurrently (the manual path
3472
+ * has no drain lease to exclude it). Entries are dropped once settled.
3611
3473
  */
3612
3474
  _close_locks = /* @__PURE__ */ new Map();
3613
3475
  /**
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.
3476
+ * Run `work` under the per-stream close lock. Serializes close
3477
+ * critical sections for the same stream (windowed prunes and full
3478
+ * closes) while letting different streams proceed in parallel.
3617
3479
  */
3618
3480
  _with_close_lock(stream, work) {
3619
3481
  const prev = this._close_locks.get(stream) ?? Promise.resolve();
@@ -3640,11 +3502,11 @@ var Act = class {
3640
3502
  * @param states Merged map of state name → state definition
3641
3503
  * @param batch_handlers Static-target projection batch handlers (target → handler)
3642
3504
  * @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.
3505
+ * @param lanes Declared drain lanes. The builder collects
3506
+ * these from `.withLane(...)` calls; one `DrainController` runs
3507
+ * per lane, plus the implicit `"default"`.
3646
3508
  * @param patch_fn The per-event patch step selected once by the builder
3647
- * from `ActOptions.validateFoldedState` (ACT-1238) — `bare_patch` by
3509
+ * from `ActOptions.validateFoldedState` — `bare_patch` by
3648
3510
  * default, `validating_patch` when the flag is on. The builder uses
3649
3511
  * the same value for its projection-fold handlers, so there is a
3650
3512
  * single selection site. Defaults to `bare_patch` for direct
@@ -3659,16 +3521,15 @@ var Act = class {
3659
3521
  this._ports = options.scoped ?? default_scope();
3660
3522
  const ports = this._ports;
3661
3523
  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(...)`.
3524
+ // Getters, not a spread: the singletons resolve lazily, so a later
3525
+ // `store(...)` / `cache(...)` still takes effect.
3666
3526
  get store() {
3667
3527
  return ports.store;
3668
3528
  },
3669
3529
  get cache() {
3670
3530
  return ports.cache;
3671
3531
  },
3532
+ // Parsed per build, so a bad window throws on every build.
3672
3533
  autoclose_window: resolveAutocloseConfig(options).autocloseWindow
3673
3534
  });
3674
3535
  this._correlator = options.correlator ?? default_correlator;
@@ -3676,8 +3537,6 @@ var Act = class {
3676
3537
  this._cd = build_drain(this._logger);
3677
3538
  this._handle = build_handle({
3678
3539
  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
3540
  reaction_scope: make_reaction_scope({
3682
3541
  do: this._bound_do,
3683
3542
  load: this._bound_load,
@@ -3712,16 +3571,8 @@ var Act = class {
3712
3571
  resolveCircuitBreakerConfig(options.circuitBreaker),
3713
3572
  {
3714
3573
  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()`.
3574
+ // When the cooldown elapses, settle once: its scan or claim is the
3575
+ // half-open probe that closes or re-opens the breaker.
3725
3576
  on_retry: () => {
3726
3577
  this.settle({ debounceMs: 0 });
3727
3578
  }
@@ -3729,12 +3580,9 @@ var Act = class {
3729
3580
  );
3730
3581
  }
3731
3582
  /**
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).
3583
+ * One DrainController per active lane, plus the implicit "default" unless
3584
+ * `onlyLanes` excludes it. Apps that declare no lanes pass no lane filter
3585
+ * to `claim`.
3738
3586
  */
3739
3587
  _build_drain_controllers(options, lanes) {
3740
3588
  const all_lanes = ["default", ...lanes.map((l) => l.name)];
@@ -3753,11 +3601,7 @@ var Act = class {
3753
3601
  handle_batch: this._handle_batch,
3754
3602
  on_acked: (acked) => this.emit("acked", acked),
3755
3603
  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.
3604
+ // Reaction-requested close: the same machinery as `app.close`.
3761
3605
  on_close: async (targets) => {
3762
3606
  const close_actor = { id: "$close", name: "close" };
3763
3607
  const result = await run_close_cycle(targets, {
@@ -3774,12 +3618,7 @@ var Act = class {
3774
3618
  this.emit("closed", result);
3775
3619
  },
3776
3620
  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
3621
  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
3622
  lane: single_default_lane ? void 0 : name,
3784
3623
  defaults: cfg && {
3785
3624
  streamLimit: cfg.streamLimit,
@@ -3793,17 +3632,9 @@ var Act = class {
3793
3632
  return controllers;
3794
3633
  }
3795
3634
  /**
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.
3635
+ * Startup advisory naming declared lanes that `onlyLanes` leaves without a
3636
+ * controller here. One process can't check that the cluster covers every
3637
+ * lane, so it reports its own gaps.
3807
3638
  */
3808
3639
  _advise_orphaned_lanes(options, lanes) {
3809
3640
  if (!options.onlyLanes || options.onlyLanes.length === 0) return;
@@ -3817,25 +3648,15 @@ var Act = class {
3817
3648
  `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
3649
  );
3819
3650
  }
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
- */
3651
+ /** Audit deps, built after the controllers so the lane set is final. */
3826
3652
  _build_audit_deps() {
3827
3653
  return {
3828
3654
  store,
3829
3655
  logger: this._logger,
3830
3656
  event_to_state: this._event_to_state,
3831
3657
  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.
3658
+ // Declared lanes, not this process's controllers: a lane another
3659
+ // worker drains is not `unknown-lane`.
3839
3660
  declared_lanes: /* @__PURE__ */ new Set(["default", ...this._lanes.map((l) => l.name)]),
3840
3661
  routed_events: new Set(this._event_to_lanes.keys())
3841
3662
  };
@@ -3851,10 +3672,8 @@ var Act = class {
3851
3672
  static_targets: classification.static_targets,
3852
3673
  cd: this._cd,
3853
3674
  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.
3675
+ // Declared lanes (not active ones): a lane another process claims is
3676
+ // still a valid destination.
3858
3677
  declared_lanes: /* @__PURE__ */ new Set([
3859
3678
  "default",
3860
3679
  ...this._lanes.map((l) => l.name)
@@ -3862,26 +3681,14 @@ var Act = class {
3862
3681
  on_init: () => {
3863
3682
  if (this._drain && this._reactive_events.size > 0) this._arm_all();
3864
3683
  },
3865
- // Cold-start defer re-seed (#1221). Skipped on writer-only instances
3866
- // (`drain: false`) — they run no local controllers to re-arm.
3867
3684
  on_init_async: this._drain ? () => this._seed_persisted_defers() : void 0
3868
3685
  });
3869
3686
  }
3870
3687
  /**
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.
3688
+ * At cold start, re-seed each lane controller's local wake from the
3689
+ * persisted future `deferred_at`, so an idle deferred stream (an
3690
+ * autoclose waiting out its window) still fires on time. Streams on lanes
3691
+ * this instance doesn't run are skipped.
3885
3692
  */
3886
3693
  async _seed_persisted_defers() {
3887
3694
  const now = Date.now();
@@ -3895,10 +3702,6 @@ var Act = class {
3895
3702
  _build_settle(options) {
3896
3703
  return new SettleLoop(
3897
3704
  {
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
3705
  init: () => this._scoped(() => this._correlate.init()),
3903
3706
  checkpoint: () => this._correlate.checkpoint,
3904
3707
  correlate: (q) => this._correlate_scanned(q, true),
@@ -3916,19 +3719,11 @@ var Act = class {
3916
3719
  * already in flight a bounded chance to finish, then remove lifecycle
3917
3720
  * listeners and tear down the cross-process notify subscription.
3918
3721
  *
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.
3722
+ * Scheduling stops first, then in-flight cycles get up to `graceMs` to
3723
+ * reach their `ack` (an abandoned handler holds its lease until it
3724
+ * expires). Listeners come off after the wait, so they still see work that
3725
+ * finished during it. The budget is a ceiling, not a delay; when it runs
3726
+ * out, teardown proceeds anyway.
3932
3727
  *
3933
3728
  * Idempotent — repeated calls return the same promise, and the first
3934
3729
  * call's `graceMs` is the one that applies. Registered automatically with
@@ -3946,7 +3741,7 @@ var Act = class {
3946
3741
  this.stop_correlations();
3947
3742
  const disposer = await this._notify_disposer;
3948
3743
  if (disposer) await disposer();
3949
- this.stop_settling();
3744
+ this._settle.stop();
3950
3745
  this._breaker.stop();
3951
3746
  for (const c of this._drain_controllers.values()) c.stop();
3952
3747
  await this._await_inflight(options?.graceMs);
@@ -3961,26 +3756,10 @@ var Act = class {
3961
3756
  * whichever comes first. Cycle promises never reject (`drain()` contains
3962
3757
  * its own errors), so this never throws.
3963
3758
  *
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.
3759
+ * An omitted budget is the largest `leaseMillis` among lanes with a cycle
3760
+ * in flight (the drain's fallback for lanes that pinned none, or pinned
3761
+ * 0, which is the same as none), with an in-flight settle counting on the
3762
+ * fallback, capped at the maximum. Idle lanes don't count.
3984
3763
  */
3985
3764
  _derive_grace_ms(running, settling) {
3986
3765
  let max = settling ? DEFAULT_SHUTDOWN_GRACE_MS : 0;
@@ -4253,7 +4032,7 @@ var Act = class {
4253
4032
  }
4254
4033
  /**
4255
4034
  * Wipe the sensitive-data payload for every event on the stream — see
4256
- * {@link IAct.forget}. Application-level half of #566.
4035
+ * {@link IAct.forget}.
4257
4036
  *
4258
4037
  * Throws on adapters without `Store.forget_pii`, invalidates the cache
4259
4038
  * entry for the stream, emits the `forgotten` lifecycle event with the
@@ -4294,7 +4073,7 @@ var Act = class {
4294
4073
  *
4295
4074
  * Call `correlate()` before `drain()`. It is not only how dynamic targets
4296
4075
  * are discovered: a stream is claimable while `at < correlated_at`, and
4297
- * `correlate` is the only component that raises that mark (#1487), so a
4076
+ * `correlate` is the only component that raises that mark, so a
4298
4077
  * commit no correlate has seen is not drainable — including for static
4299
4078
  * targets, which were served by a probe of the event log before. For a
4300
4079
  * higher-level API that handles debouncing, correlation, and signaling
@@ -4327,14 +4106,14 @@ var Act = class {
4327
4106
  return { fetched: [], leased: [], acked: [], blocked: [] };
4328
4107
  return this._scoped(() => this._drain_all(options));
4329
4108
  }
4330
- /** Arm every active lane controller (ACT-1103). */
4109
+ /** Arm every active lane controller. */
4331
4110
  _arm_all() {
4332
4111
  this._correlate.arm();
4333
4112
  for (const c of this._drain_controllers.values()) c.arm();
4334
4113
  }
4335
4114
  /**
4336
4115
  * Arm only the lane controllers whose reactions match the supplied
4337
- * event names (ACT-1103 selective arming). Events with any dynamic
4116
+ * event names (selective arming). Events with any dynamic
4338
4117
  * resolver fall back to `_arm_all()` via the `"all"` sentinel — the
4339
4118
  * resolver's lane isn't known until correlate runs the function.
4340
4119
  * Events with no reactions are skipped; `_event_to_lanes` doesn't
@@ -4438,7 +4217,7 @@ var Act = class {
4438
4217
  return { subscribed, last_id };
4439
4218
  }
4440
4219
  /**
4441
- * `correlate` plus whether the pass actually read the store (#1510).
4220
+ * `correlate` plus whether the pass actually read the store.
4442
4221
  *
4443
4222
  * The settle loop needs that extra bit to decide whether the pass carries a
4444
4223
  * circuit-breaker health signal, and a disarmed pass carries none. It stays
@@ -4699,7 +4478,7 @@ var Act = class {
4699
4478
  });
4700
4479
  }
4701
4480
  /**
4702
- * Operator-driven store audit (#723).
4481
+ * Operator-driven store audit.
4703
4482
  *
4704
4483
  * Walks the connected store and yields per-category findings —
4705
4484
  * each tagged with the remediation it suggests. Same operator-
@@ -4751,7 +4530,7 @@ var Act = class {
4751
4530
  * Bulk-update scheduling priority for streams matching `filter`.
4752
4531
  *
4753
4532
  * Operator-grade override of the `claim()` lagging-frontier
4754
- * ordering (ACT-102). Useful when a long-running replay needs to
4533
+ * ordering. Useful when a long-running replay needs to
4755
4534
  * jump ahead of other lagging streams, or when a no-longer-urgent
4756
4535
  * job should yield slots back to the rest. Build-time priorities
4757
4536
  * (set via the resolver's `priority` field) are subject to a
@@ -4848,12 +4627,12 @@ var Act = class {
4848
4627
  */
4849
4628
  /**
4850
4629
  * After a close, forget any target whose subscription row the truncate
4851
- * removed, so a later correlate can re-subscribe it (#1398). Restart
4630
+ * removed, so a later correlate can re-subscribe it. Restart
4852
4631
  * targets keep their row, so only fully-retired streams are forgotten.
4853
4632
  */
4854
4633
  /**
4855
4634
  * Advance correlation until the read cursor reaches `until`, and report
4856
- * where it landed (#1487). Used by the close cycle's safety probe, which
4635
+ * where it landed. Used by the close cycle's safety probe, which
4857
4636
  * cannot judge a subscription's pending work over events correlate has
4858
4637
  * not resolved yet.
4859
4638
  *
@@ -4879,13 +4658,12 @@ var Act = class {
4879
4658
  * A tombstone seed means the stream was retired; a snapshot seed means it
4880
4659
  * was restarted and is still consuming.
4881
4660
  *
4882
- * `truncate` no longer removes the subscription row (#1527), so this is no
4661
+ * `truncate` no longer removes the subscription row, so this is no
4883
4662
  * longer repairing damage the close itself did. It still matters, because
4884
4663
  * the row can disappear later: reclaiming retired subscriptions is an
4885
4664
  * operator job now, and that `DELETE` can land while this process is
4886
4665
  * 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
4666
+ * an operator removed, which is a silent-no-delivery failure — a reaction whose target is named after the stream would never
4889
4667
  * be re-registered.
4890
4668
  */
4891
4669
  _forget_closed_subscriptions(result) {
@@ -5160,7 +4938,7 @@ function reaction_on(event, events, builder) {
5160
4938
  const reaction = {
5161
4939
  handler: schedule ? make_deferred(handler, schedule) : handler,
5162
4940
  resolver: _this_,
5163
- // #1269: validate the whole bag at the declaration site so a bad
4941
+ // Validate the whole bag at the declaration site so a bad
5164
4942
  // `maxRetries`/`backoff`/`blockOnError` throws ZodError at build,
5165
4943
  // not a NaN gate on the first retry.
5166
4944
  options: resolveReactionConfig({
@@ -5362,7 +5140,7 @@ function act() {
5362
5140
  spec.flush,
5363
5141
  spec.config,
5364
5142
  patch_fn,
5365
- // Head loads strip sensitive keys like the warm path (#1320).
5143
+ // Head loads strip sensitive keys like the warm path.
5366
5144
  registry.sensitive_fields
5367
5145
  )
5368
5146
  )
@@ -5868,7 +5646,7 @@ var CsvFile = class {
5868
5646
  name: fields[1],
5869
5647
  // Revive dates like every Store adapter does — a Date in an event
5870
5648
  // payload must not depend on whether it came back through a store or
5871
- // through a CSV restore (#1399). The `created` column below has
5649
+ // through a CSV restore. The `created` column below has
5872
5650
  // always been parsed explicitly; the JSON columns were missed.
5873
5651
  data: JSON.parse(fields[2]),
5874
5652
  stream: fields[3],