@yielded/agent-platform-cloudflare 0.1.0-beta.174 → 0.1.0-beta.175

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 (30) hide show
  1. package/dist/{Alarm-4J9B8Fg8.mjs → Alarm-B44efvB1.mjs} +111 -74
  2. package/dist/Alarm-B44efvB1.mjs.map +1 -0
  3. package/dist/Alarm.d.mts +2 -0
  4. package/dist/Alarm.mjs +1 -1
  5. package/dist/CloudflareScheduling.mjs +2 -2
  6. package/dist/CloudflareSubscriptions.mjs +2 -2
  7. package/dist/{CloudflareThreadClient-DU548EEj.mjs → CloudflareThreadClient-Ai3MTs3X.mjs} +4 -4
  8. package/dist/CloudflareThreadClient-Ai3MTs3X.mjs.map +1 -0
  9. package/dist/{CloudflareThreadClient-lTm6baDP.d.mts → CloudflareThreadClient-HO_3rkM7.d.mts} +362 -362
  10. package/dist/CloudflareThreadClient.d.mts +1 -1
  11. package/dist/CloudflareThreadClient.mjs +1 -1
  12. package/dist/{ThreadObject-BLYgzcdT.d.mts → ThreadObject-CxNlhoPL.d.mts} +13 -13
  13. package/dist/{ThreadObject-C2LF3btz.mjs → ThreadObject-DGvlHWYi.mjs} +42 -43
  14. package/dist/ThreadObject-DGvlHWYi.mjs.map +1 -0
  15. package/dist/ThreadObject.d.mts +1 -1
  16. package/dist/ThreadObject.mjs +1 -1
  17. package/dist/WakeScheduler.mjs +1 -1
  18. package/dist/index.d.mts +2 -2
  19. package/dist/index.mjs +3 -3
  20. package/dist/{prepared-admission-BoUPHSNQ.mjs → prepared-admission-DYdffQ8K.mjs} +2 -2
  21. package/dist/{prepared-admission-BoUPHSNQ.mjs.map → prepared-admission-DYdffQ8K.mjs.map} +1 -1
  22. package/package.json +1 -1
  23. package/src/Alarm.ts +211 -116
  24. package/src/CloudflareThreadClient.ts +3 -2
  25. package/src/ThreadObject.ts +17 -22
  26. package/src/internal/layers.ts +55 -34
  27. package/src/internal/message-delivery.ts +61 -37
  28. package/dist/Alarm-4J9B8Fg8.mjs.map +0 -1
  29. package/dist/CloudflareThreadClient-DU548EEj.mjs.map +0 -1
  30. package/dist/ThreadObject-C2LF3btz.mjs.map +0 -1
@@ -624,6 +624,14 @@ const recoveryEvent = (fault, submissionId, transition, occurredAt) => ({
624
624
  firstFailedAt: fault.firstFailedAt,
625
625
  failure: fault.failure
626
626
  });
627
+ /** Observe already-owned waves without creating one waiter fiber for each wave. */
628
+ const awaitAnyCompletion = Effect.fnUntraced(function* (fibers, revision) {
629
+ const mutations = yield* ThreadMutationGate;
630
+ return yield* Effect.acquireUseRelease(Effect.sync(() => []), (observers) => Effect.callback((resume) => {
631
+ observers.push(mutations.observeChange(revision, () => resume(Effect.succeed("scan"))));
632
+ for (const fiber of fibers) observers.push(fiber.addObserver(() => resume(Effect.succeed("completed"))));
633
+ }), (observers) => Effect.sync(() => observers.forEach((remove) => remove())));
634
+ });
627
635
  /** Post-native delivery shares a finite connection budget across independent host lanes. */
628
636
  const afterNativeDispatchConcurrency = 2;
629
637
  const NativeWorkCursor = Schema.Struct({
@@ -709,12 +717,22 @@ var ThreadMutationGate = class ThreadMutationGate extends Context.Service()("@ef
709
717
  const activeLanes = /* @__PURE__ */ new Map();
710
718
  const generationGate = yield* Semaphore.make(1);
711
719
  let revision = 0;
712
- let changed = yield* Deferred.make();
713
- const notify = Effect.gen(function* () {
714
- const previous = changed;
715
- changed = yield* Deferred.make();
720
+ const listeners = /* @__PURE__ */ new Set();
721
+ const observeChange = (observed, listener) => {
722
+ if (observed !== revision) {
723
+ listener();
724
+ return () => {};
725
+ }
726
+ listeners.add(listener);
727
+ return () => {
728
+ listeners.delete(listener);
729
+ };
730
+ };
731
+ const notify = Effect.sync(() => {
716
732
  revision++;
717
- yield* Deferred.succeed(previous, void 0);
733
+ const pending = [...listeners];
734
+ listeners.clear();
735
+ for (const listener of pending) listener();
718
736
  });
719
737
  const minimumAlarmDelay = Math.max(1, Math.ceil(config.alarmBackoffBase / 2));
720
738
  const runTransaction = yield* makeStorageOperation;
@@ -740,8 +758,8 @@ var ThreadMutationGate = class ThreadMutationGate extends Context.Service()("@ef
740
758
  dirty: state.dirty + 1n
741
759
  })));
742
760
  }
743
- const next$4 = next(dueQueue.read());
744
- if (Number.isFinite(next$4)) checkpoint.earlier(Math.max(next$4, now + minimumAlarmDelay));
761
+ const next$2 = next(dueQueue.read());
762
+ if (Number.isFinite(next$2)) checkpoint.earlier(Math.max(next$2, now + minimumAlarmDelay));
745
763
  };
746
764
  yield* runAlarmTransaction("schedule maintenance lane", enroll);
747
765
  yield* notify;
@@ -818,7 +836,11 @@ var ThreadMutationGate = class ThreadMutationGate extends Context.Service()("@ef
818
836
  recordProgress,
819
837
  activeLanes: Effect.sync(() => new Set(activeLanes.keys())),
820
838
  revision: Effect.sync(() => revision),
821
- awaitChange: (observed) => Effect.suspend(() => observed === revision ? Deferred.await(changed) : Effect.void),
839
+ observeChange,
840
+ awaitChange: (observed) => Effect.callback((resume) => {
841
+ const remove = observeChange(observed, () => resume(Effect.void));
842
+ return Effect.sync(remove);
843
+ }),
822
844
  withSnapshot: (body) => generationGate.withPermit(Effect.flatMap(Ref.get(activeMutations), body))
823
845
  });
824
846
  }));
@@ -849,6 +871,7 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
849
871
  const runtime = yield* DurableAgentRuntime;
850
872
  const recoveryConfig = yield* DurableRuntimeConfig;
851
873
  const ledger = yield* SubmissionLedger;
874
+ const listNonterminal = ledger.listNonterminal ?? Stream.runCollect(ledger.scanNonterminal);
852
875
  const wakes = yield* WakeScheduler;
853
876
  const hints = yield* DurableAlarmService;
854
877
  const alarms = yield* ThreadMaintenanceAlarm;
@@ -865,6 +888,8 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
865
888
  const messages = yield* ThreadMessageDelivery;
866
889
  const host = yield* ThreadHostMaintenance;
867
890
  const framework = yield* ThreadNativeMaintenance;
891
+ const placement = yield* Effect.serviceOption(ThreadObjectPlacement);
892
+ const nativeThread = Option.isSome(placement) ? placement.value.threadId : void 0;
868
893
  const nativeDispatchConcurrency = () => framework.singleThreadRuntime === runtime ? 1 : 2;
869
894
  for (const lane of host.lanes) yield* Schema.decodeEffect(HostLaneId)(lane.id).pipe(Effect.mapError(alarmFailure("maintenance lane ID")));
870
895
  const recoveryEvents = Option.getOrElse(yield* Effect.serviceOption(ThreadRecoveryEvents), () => ThreadRecoveryEvents.of({ publish: () => Effect.void }));
@@ -914,8 +939,8 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
914
939
  const now = yield* Clock.currentTimeMillis;
915
940
  const claimed = yield* runAlarmTransaction("charge maintenance attempt", async (_transaction, checkpoint) => {
916
941
  const claimed = dueQueue.claim(selected, now);
917
- const next$1 = next(dueQueue.read());
918
- if (Number.isFinite(next$1)) checkpoint.at(Math.max(now + minimumAlarmDelay, next$1));
942
+ const next$3 = next(dueQueue.read());
943
+ if (Number.isFinite(next$3)) checkpoint.at(Math.max(now + minimumAlarmDelay, next$3));
919
944
  else checkpoint.cancel();
920
945
  return claimed;
921
946
  });
@@ -1008,7 +1033,7 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1008
1033
  for (const blocked of result.blocked) threads.set(blocked.threadId, blocked.failure);
1009
1034
  if (threads.size === 0 || [...threads].every(([threadId, failure]) => failure === void 0 && recovery.loaded.has(threadId) && !recovery.faults.has(threadId))) return /* @__PURE__ */ new Map();
1010
1035
  const now = yield* Clock.currentTimeMillis;
1011
- const submissions = current ?? (result.blocked.length === 0 ? [] : yield* Stream.runCollect(ledger.scanNonterminal));
1036
+ const submissions = current ?? (result.blocked.length === 0 ? [] : yield* listNonterminal);
1012
1037
  yield* failpoint.hit("maintenance:recovery-status:before");
1013
1038
  const retained = yield* runTransaction("record Thread recovery faults", () => dueQueue.transaction(async (transaction) => {
1014
1039
  const events = [];
@@ -1078,6 +1103,7 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1078
1103
  do {
1079
1104
  const result = yield* runtime.runRecovery({
1080
1105
  threadId,
1106
+ deferUnclaimedAdmissions: true,
1081
1107
  ...cursor === void 0 ? {} : { cursor }
1082
1108
  }).pipe(Effect.provideService(CurrentNativeSource, true));
1083
1109
  const faults = yield* recordRecoveryFaults(result, recovery, void 0, threadId);
@@ -1124,8 +1150,8 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1124
1150
  if (!initialized) await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(state));
1125
1151
  const native = state.dirty > state.processed ? state.retry?.generation === state.dirty ? state.retry.notBefore : rows.find((row) => row.id === "effect-agent:native")?.dueAt ?? now + minimumAlarmDelay : null;
1126
1152
  dueQueue.checkpointNative(native);
1127
- const next$3 = next(dueQueue.read());
1128
- if (Number.isFinite(next$3)) checkpoint.earlier(Math.max(now + minimumAlarmDelay, next$3));
1153
+ const next$1 = next(dueQueue.read());
1154
+ if (Number.isFinite(next$1)) checkpoint.earlier(Math.max(now + minimumAlarmDelay, next$1));
1129
1155
  });
1130
1156
  yield* failpoint.hit("maintenance:ensure:after");
1131
1157
  });
@@ -1199,8 +1225,8 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1199
1225
  const charged = observed.charged.get(row.id) === row.revision ? row : dueQueue.claim(row, now);
1200
1226
  if (charged !== void 0) dueQueue.complete(charged, now + backoffDelay(charged.stalls, jitter));
1201
1227
  }
1202
- const next$5 = next(dueQueue.read());
1203
- if (Number.isFinite(next$5)) checkpoint.at(Math.max(now + minimumAlarmDelay, next$5));
1228
+ const next$4 = next(dueQueue.read());
1229
+ if (Number.isFinite(next$4)) checkpoint.at(Math.max(now + minimumAlarmDelay, next$4));
1204
1230
  else checkpoint.cancel();
1205
1231
  });
1206
1232
  }));
@@ -1291,11 +1317,14 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1291
1317
  const { state } = await readMaintenanceState(ctx.storage);
1292
1318
  return {
1293
1319
  scannedGeneration: state.dirty,
1294
- afterWorkThread: state.lastRecoveredThreadId
1320
+ afterWorkThread: framework.singleThreadRuntime === runtime && state.lastRecoveredThreadId === nativeThread ? void 0 : state.lastRecoveredThreadId
1295
1321
  };
1296
1322
  });
1297
- const current = yield* Stream.runCollect(ledger.scanNonterminal);
1298
- let workOwners = yield* runtime.discoverWorkThreads({
1323
+ const current = yield* listNonterminal;
1324
+ let workOwners = framework.singleThreadRuntime === runtime && nativeThread !== void 0 && current.some((submission) => submission.threadId === nativeThread) ? {
1325
+ threadIds: [nativeThread],
1326
+ afterThreadId: void 0
1327
+ } : yield* runtime.discoverWorkThreads({
1299
1328
  limit: 32,
1300
1329
  ...afterWorkThread === void 0 ? {} : { afterThreadId: afterWorkThread }
1301
1330
  }).pipe(Effect.provideService(CurrentNativeSource, true));
@@ -1419,7 +1448,7 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1419
1448
  nextAttemptAt: void 0,
1420
1449
  dispatched: selection.selected.length > 0
1421
1450
  };
1422
- const remaining = yield* Stream.runCollect(ledger.scanNonterminal);
1451
+ const remaining = yield* listNonterminal;
1423
1452
  const waitingHeads = /* @__PURE__ */ new Map();
1424
1453
  const autonomous = recovery.pending.size > 0 || recovery.discoveryPending || recoveryFaults.size > 0 || recovery.retryAtMillis !== void 0 || remaining.some((snapshot) => {
1425
1454
  if (snapshot.state === "unknown" && waiting(snapshot)) return false;
@@ -1494,7 +1523,8 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1494
1523
  });
1495
1524
  });
1496
1525
  const dispatch = Effect.fnUntraced(function* (yieldAfter, dispatchUntil, observed) {
1497
- const notified = (yield* Stream.toPull(wakes.wakes)).pipe(Effect.asVoid, Effect.catch(() => Effect.never));
1526
+ const leanSelection = framework.singleThreadRuntime === runtime && publication === emptyPublication && host.lanes.length === 0 && framework.lanes.length === 0;
1527
+ const notified = leanSelection ? Effect.never : (yield* Stream.toPull(wakes.wakes)).pipe(Effect.asVoid, Effect.catch(() => Effect.never));
1498
1528
  const started = yield* beginNative(observed);
1499
1529
  yield* mutations.withSnapshot(() => Effect.gen(function* () {
1500
1530
  const queued = yield* queueSnapshot;
@@ -1531,8 +1561,35 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1531
1561
  repaired: false,
1532
1562
  discoveryPending: false
1533
1563
  };
1534
- const recoveryFiber = yield* fork(Effect.gen(function* () {
1535
- for (const threadId of yield* Deferred.await(recovery.queue)) {
1564
+ let recoveryFiber;
1565
+ let backfill;
1566
+ const dispatch = {
1567
+ scope: auxiliaryScope,
1568
+ active: /* @__PURE__ */ new Map(),
1569
+ deferred: /* @__PURE__ */ new Set(),
1570
+ dispatched: 0,
1571
+ settled: 0,
1572
+ progressed: false,
1573
+ needsCheckpoint: false
1574
+ };
1575
+ let native;
1576
+ let result;
1577
+ let backlog;
1578
+ if (leanSelection) {
1579
+ result = yield* advance(started, yieldAfter, observed, recovery, dispatch);
1580
+ recovery.started = true;
1581
+ yield* Deferred.succeed(recovery.queue, []);
1582
+ backlog = yield* Deferred.await(recovery.queue);
1583
+ } else {
1584
+ native = yield* fork(advance(started, yieldAfter, observed, recovery, dispatch));
1585
+ result = {
1586
+ phase: "caught-up",
1587
+ nonterminal: started.nonterminal,
1588
+ nextAttemptAt: void 0
1589
+ };
1590
+ }
1591
+ if (backlog === void 0 || backlog.length > 0) recoveryFiber = yield* fork(Effect.gen(function* () {
1592
+ for (const threadId of backlog ?? (yield* Deferred.await(recovery.queue))) {
1536
1593
  yield* failpoint.hit("maintenance:select:before");
1537
1594
  yield* runTransaction("select old recovery lane", () => dueQueue.transaction(async (transaction) => {
1538
1595
  const { state } = await readMaintenanceState(transaction);
@@ -1547,31 +1604,11 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1547
1604
  if (!recovery.faults.has(threadId)) yield* wakes.notify(threadId);
1548
1605
  }
1549
1606
  }));
1550
- const backfill = yield* fork(Effect.gen(function* () {
1551
- if ((yield* mutations.activeLanes).has("effect-agent:projection")) return;
1552
- const row = (yield* queueSnapshot).find((row) => row.id === Projection);
1553
- if (row?.dueAt === null || row === void 0 || row.dueAt > (yield* Clock.currentTimeMillis)) return;
1554
- return yield* runQueued(row, projection.drain.pipe(Effect.andThen(projection.pendingDeadline)), observed).pipe(Effect.timeoutOption(config.projectionDispatchTimeoutMillis));
1555
- }));
1556
- let backfillObserved = false;
1557
- let recoveryObserved = false;
1558
- const dispatch = {
1559
- scope: auxiliaryScope,
1560
- active: /* @__PURE__ */ new Map(),
1561
- deferred: /* @__PURE__ */ new Set(),
1562
- dispatched: 0,
1563
- settled: 0,
1564
- progressed: false,
1565
- needsCheckpoint: false
1566
- };
1567
- let native = yield* fork(advance(started, yieldAfter, observed, recovery, dispatch));
1568
- let result = {
1569
- phase: "caught-up",
1570
- nonterminal: started.nonterminal,
1571
- nextAttemptAt: void 0
1572
- };
1607
+ const projectionRow = (yield* queueSnapshot).find((row) => row.id === Projection);
1608
+ if (projectionRow !== void 0 && projectionRow.dueAt !== null && projectionRow.dueAt <= (yield* Clock.currentTimeMillis) && !(yield* mutations.activeLanes).has("effect-agent:projection")) backfill = yield* fork(runQueued(projectionRow, projection.drain.pipe(Effect.andThen(projection.pendingDeadline)), observed).pipe(Effect.timeoutOption(config.projectionDispatchTimeoutMillis), Effect.asVoid));
1573
1609
  let phase = result.phase;
1574
- let nativeCheck = false;
1610
+ let nativeCheck = result.dispatched === true && dispatch.active.size < nativeDispatchConcurrency();
1611
+ observed.nativeOnly = dispatch.active.size > 0;
1575
1612
  const until = DateTime.toEpochMillis(yieldAfter);
1576
1613
  const dispatchEnd = DateTime.toEpochMillis(dispatchUntil);
1577
1614
  while (true) {
@@ -1599,18 +1636,16 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1599
1636
  if (exit.value === 0) dispatch.deferred.add(threadId);
1600
1637
  nativeCheck = true;
1601
1638
  }
1602
- if (!recoveryObserved && recoveryFiber.pollUnsafe() !== void 0) {
1639
+ if (recoveryFiber?.pollUnsafe() !== void 0) {
1603
1640
  yield* Fiber.join(recoveryFiber);
1604
- recoveryObserved = true;
1641
+ recoveryFiber = void 0;
1605
1642
  dispatch.scanGeneration = void 0;
1606
1643
  nativeCheck ||= recovery.needsCheckpoint;
1607
1644
  }
1608
- if (!backfillObserved) {
1609
- const exit = backfill.pollUnsafe();
1610
- if (exit !== void 0) {
1611
- backfillObserved = true;
1612
- if (Exit.isFailure(exit)) failure ??= exit.cause;
1613
- }
1645
+ const backfillExit = backfill?.pollUnsafe();
1646
+ if (backfillExit !== void 0) {
1647
+ backfill = void 0;
1648
+ if (Exit.isFailure(backfillExit)) failure ??= backfillExit.cause;
1614
1649
  }
1615
1650
  for (const lane of lanes) {
1616
1651
  const exit = lane.fiber?.pollUnsafe();
@@ -1668,11 +1703,11 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1668
1703
  return yield* wave.run;
1669
1704
  }), observed).pipe(Effect.asVoid));
1670
1705
  }
1671
- if (native === void 0 && dispatch.active.size === 0 && recoveryObserved && !recovery.needsCheckpoint && backfillObserved && delivery === void 0 && lanes.every((lane) => lane.fiber === void 0)) break;
1706
+ if (native === void 0 && dispatch.active.size === 0 && recoveryFiber === void 0 && !recovery.needsCheckpoint && backfill === void 0 && delivery === void 0 && lanes.every((lane) => lane.fiber === void 0)) break;
1672
1707
  if (native === void 0 && nativeCheck && dispatch.active.size < nativeDispatchConcurrency()) {
1673
1708
  nativeCheck = false;
1674
1709
  const nativeCheckpoint = dispatch.needsCheckpoint && dispatch.active.size === 0;
1675
- const checkpoint = recoveryObserved && recovery.needsCheckpoint || nativeCheckpoint;
1710
+ const checkpoint = recoveryFiber === void 0 && recovery.needsCheckpoint || nativeCheckpoint;
1676
1711
  if (checkpoint) recovery.needsCheckpoint = false;
1677
1712
  const reserved = new Set(dispatch.active.keys());
1678
1713
  native = yield* fork(Effect.gen(function* () {
@@ -1682,18 +1717,19 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1682
1717
  }
1683
1718
  const next = Math.min(native === void 0 ? result.nextAttemptAt ?? Infinity : Infinity, ...queued.flatMap((row) => row.id !== "effect-agent:native" && row.dueAt !== null && row.dueAt > now ? [row.dueAt] : []), until);
1684
1719
  const completing = [
1685
- ...native === void 0 ? [] : [native],
1720
+ native,
1686
1721
  ...dispatch.active.values(),
1687
- ...recoveryObserved ? [] : [recoveryFiber],
1688
- ...backfillObserved ? [] : [backfill],
1689
- ...delivery === void 0 ? [] : [delivery],
1690
- ...lanes.flatMap((lane) => lane.fiber === void 0 ? [] : [lane.fiber])
1691
- ];
1692
- if ((yield* Effect.raceAllFirst([...completing.map((fiber) => Fiber.await(fiber).pipe(Effect.as("completed"))), Effect.raceAllFirst([
1693
- notified,
1694
- mutations.awaitChange(queueRevision),
1695
- Effect.sleep(Math.max(0, next - now))
1696
- ]).pipe(Effect.as("scan"))])) === "scan") nativeCheck = true;
1722
+ recoveryFiber,
1723
+ backfill,
1724
+ delivery,
1725
+ ...lanes.map((lane) => lane.fiber)
1726
+ ].filter((fiber) => fiber !== void 0);
1727
+ const changed = awaitAnyCompletion(completing, queueRevision);
1728
+ if ((yield* leanSelection && native === void 0 && dispatch.active.size === 1 && completing.length === 1 && !queued.some((row) => row.id !== "effect-agent:native" && row.dueAt !== null && row.dueAt > now && row.dueAt < until) ? changed : Effect.raceAllFirst([
1729
+ changed,
1730
+ ...leanSelection ? [] : [notified.pipe(Effect.as("scan"))],
1731
+ Effect.sleep(Math.max(0, next - now)).pipe(Effect.as("scan"))
1732
+ ])) === "scan") nativeCheck = true;
1697
1733
  }
1698
1734
  if (native !== void 0) {
1699
1735
  result = yield* Fiber.join(native);
@@ -1712,9 +1748,10 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1712
1748
  for (const fiber of [
1713
1749
  recoveryFiber,
1714
1750
  backfill,
1715
- ...delivery === void 0 ? [] : [delivery],
1716
- ...lanes.flatMap((lane) => lane.fiber === void 0 ? [] : [lane.fiber])
1751
+ delivery,
1752
+ ...lanes.map((lane) => lane.fiber)
1717
1753
  ]) {
1754
+ if (fiber === void 0) continue;
1718
1755
  const exit = yield* Fiber.await(fiber);
1719
1756
  if (Exit.isFailure(exit)) failure ??= exit.cause;
1720
1757
  }
@@ -1732,7 +1769,7 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1732
1769
  };
1733
1770
  });
1734
1771
  const pass = Effect.fnUntraced(function* (yieldAfter, dispatchUntil, observed) {
1735
- const concurrent = yield* Effect.exit(Effect.scoped(dispatch(yieldAfter, dispatchUntil, observed)));
1772
+ const concurrent = yield* Effect.exit(Effect.scoped(dispatch(yieldAfter, dispatchUntil, observed)).pipe(Effect.provideService(ThreadMutationGate, mutations)));
1736
1773
  const afterNative = yield* Effect.gen(function* () {
1737
1774
  const lanes = [
1738
1775
  recoveryEventLane,
@@ -1803,9 +1840,9 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1803
1840
  const { state } = await readMaintenanceState(transaction);
1804
1841
  const native = active > 0 || state.dirty > state.processed ? state.retry?.generation === state.dirty && active === 0 ? Math.max(now + minimumAlarmDelay, state.retry.notBefore) : state.dirty === observed.generation && active === 0 ? result.nextAttemptAt ?? now + minimumAlarmDelay : now + minimumAlarmDelay : Infinity;
1805
1842
  dueQueue.checkpointNative(Number.isFinite(native) ? native : null);
1806
- const next$2 = next(dueQueue.read());
1807
- if (Number.isFinite(next$2)) {
1808
- checkpoint.at(Math.max(now + minimumAlarmDelay, next$2));
1843
+ const next$5 = next(dueQueue.read());
1844
+ if (Number.isFinite(next$5)) {
1845
+ checkpoint.at(Math.max(now + minimumAlarmDelay, next$5));
1809
1846
  return "rearmed";
1810
1847
  }
1811
1848
  checkpoint.cancel();
@@ -1859,4 +1896,4 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
1859
1896
  //#endregion
1860
1897
  export { Lifecycle as _, ThreadHostMaintenance as a, Projection as b, ThreadMaintenanceFailpoint as c, ThreadNativeMaintenance as d, ThreadPublication as f, HostLaneId as g, publishCommitted as h, MaintenancePassReport as i, ThreadMessageDelivery as l, ThreadRecoveryFaultEvent as m, DurableAlarmError as n, ThreadMaintenance as o, ThreadRecoveryEvents as p, DurableAlarmService as r, ThreadMaintenanceAlarm as s, Alarm_exports as t, ThreadMutationGate as u, Messages as v, Publication as x, Native as y };
1861
1898
 
1862
- //# sourceMappingURL=Alarm-4J9B8Fg8.mjs.map
1899
+ //# sourceMappingURL=Alarm-B44efvB1.mjs.map