deepline 0.3.72 → 0.3.74

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.
@@ -1,34 +1,22 @@
1
+ import { COMPLETED_RECEIPT_CACHE_INSERT_LEASE_ID } from '../durable-receipt-execution';
1
2
  import type { ToolExecuteResult } from '../tool-result';
2
- import { createRuntimeReceiptHeartbeatSupervisor } from '../receipt-heartbeat-supervisor';
3
3
  import {
4
4
  ToolCallReceiptLeaseLostError,
5
5
  type ToolCallReceiptLease,
6
- type ToolCallReceiptRecoverySource,
7
6
  type ToolResultReceipts,
8
7
  } from './contract';
9
8
 
10
- /**
11
- * The durable state of one map-member Tool Result Receipt. This is deliberately
12
- * smaller than RuntimeStepReceipt: row persistence and provider transport are
13
- * not receipt-cohort concerns.
14
- */
15
9
  export type ToolCallReceiptRecord = {
16
10
  resultReceiptKey: string;
17
- status: 'queued' | 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
18
- result?: ToolExecuteResult;
19
- error?: unknown;
20
- lease?: ToolCallReceiptLease;
21
- leaseExpiresAt?: string | null;
22
- claimState?: 'claimed' | 'existing';
11
+ status: 'completed' | 'skipped';
12
+ result: ToolExecuteResult;
23
13
  };
24
14
 
25
15
  export type ToolCallReceiptCohortMember = {
26
- /** A caller-local identity; it is never persisted. */
27
16
  memberId: string;
28
17
  resultReceiptKey: string;
29
18
  force?: boolean;
30
19
  forceFailedRefresh?: boolean;
31
- /** Number of poll reads before a foreign/incomplete receipt is reclaimed. */
32
20
  waitMaxAttempts?: number;
33
21
  };
34
22
 
@@ -36,26 +24,6 @@ export type ToolCallReceiptCohortStore = {
36
24
  read(input: {
37
25
  resultReceiptKeys: string[];
38
26
  }): Promise<ToolCallReceiptRecord[]>;
39
- /**
40
- * The Adapter may partition this vector by refresh policy to reach a legacy
41
- * gateway that accepts one policy per RPC. Results are key-aligned by value,
42
- * not array position, so duplicates are forbidden at this seam.
43
- */
44
- claim(input: {
45
- ownerRunId: string;
46
- ownerAttempt: number;
47
- receipts: Array<{
48
- resultReceiptKey: string;
49
- force: boolean;
50
- forceFailedRefresh: boolean;
51
- reclaimRunning: boolean;
52
- }>;
53
- }): Promise<ToolCallReceiptRecord[]>;
54
- heartbeat(input: {
55
- ownerRunId: string;
56
- ownerAttempt: number;
57
- receipts: Array<{ resultReceiptKey: string; lease: ToolCallReceiptLease }>;
58
- }): Promise<ToolCallReceiptRecord[]>;
59
27
  complete(input: {
60
28
  ownerRunId: string;
61
29
  ownerAttempt: number;
@@ -65,24 +33,14 @@ export type ToolCallReceiptCohortStore = {
65
33
  result: ToolExecuteResult;
66
34
  }>;
67
35
  }): Promise<ToolCallReceiptRecord[]>;
68
- fail(input: {
69
- ownerRunId: string;
70
- ownerAttempt: number;
71
- receipts: Array<{
72
- resultReceiptKey: string;
73
- lease: ToolCallReceiptLease;
74
- error: unknown;
75
- }>;
76
- }): Promise<ToolCallReceiptRecord[]>;
77
36
  };
78
37
 
79
38
  export type ToolCallReceiptCohortMemberState =
80
39
  | {
81
40
  kind: 'completed';
82
41
  result: ToolExecuteResult;
83
- source: 'cache' | 'in_flight' | 'owner';
42
+ source: 'cache' | 'owner';
84
43
  }
85
- | { kind: 'failed'; error: unknown }
86
44
  | {
87
45
  kind: 'owned';
88
46
  resultReceiptKey: string;
@@ -95,34 +53,20 @@ export type ToolCallReceiptCohortMemberState =
95
53
  resultReceiptKey: string;
96
54
  ownerMemberId: string;
97
55
  result: Promise<ToolExecuteResult>;
98
- }
99
- | {
100
- /** A foreign receipt is being hydrated/reclaimed by the cohort. */
101
- kind: 'recovering';
102
- resultReceiptKey: string;
103
- result: Promise<ToolExecuteResult>;
104
56
  };
105
57
 
106
58
  export type ToolCallReceiptCohort = {
107
59
  member(memberId: string): ToolCallReceiptCohortMemberState;
108
- /** A native batch uses this after splitting one physical provider response. */
109
60
  complete(
110
61
  input: Array<{ memberId: string; result: ToolExecuteResult }>,
111
62
  ): Promise<Map<string, ToolExecuteResult>>;
112
63
  fail(input: Array<{ memberId: string; error: unknown }>): Promise<void>;
113
- /** One RPC for every distinct owned receipt, including queued map tail work. */
114
64
  heartbeat(): Promise<'active' | 'terminal'>;
115
- /**
116
- * Starts the cohort's ownership supervisor. Per-member receipt views only
117
- * assert this shared fence; they never fragment it into one heartbeat RPC per
118
- * provider call.
119
- */
120
65
  startHeartbeat(input: {
121
66
  intervalMs: number;
122
67
  onLeaseLost(error: ToolCallReceiptLeaseLostError): void;
123
68
  onTransientFailure?(error: unknown): void;
124
69
  }): { stop(): void; assertOwned(): void };
125
- /** Wait for foreign-receipt hydration/reclaim work started by eager acquire. */
126
70
  settle(): Promise<void>;
127
71
  };
128
72
 
@@ -130,41 +74,21 @@ export type ToolCallReceiptCohortJob = {
130
74
  acquire(input: {
131
75
  owner: { runId: string; attempt: number };
132
76
  members: ToolCallReceiptCohortMember[];
133
- /**
134
- * Return after the atomic initial claim so independently owned map rows
135
- * can start provider work while foreign rows hydrate. The default keeps
136
- * the standalone Module's all-settled acquisition contract.
137
- */
138
77
  eager?: boolean;
139
78
  }): Promise<ToolCallReceiptCohort>;
140
79
  };
141
80
 
142
- export class ToolCallReceiptCohortWaitTimeoutError extends Error {
143
- constructor(resultReceiptKey: string) {
144
- super(`Timed out waiting for Tool Result Receipt ${resultReceiptKey}.`);
145
- this.name = 'ToolCallReceiptCohortWaitTimeoutError';
146
- }
147
- }
148
-
149
81
  /**
150
- * Owns the receipt protocol for one mapped Tool Call cohort.
151
- *
152
- * Its leverage is deliberately map-specific: scalar ToolCall needs one receipt;
153
- * a map needs deduplicated bulk ownership, bounded foreign-owner recovery,
154
- * one heartbeat for undispatched work, and a terminal fanout after a native
155
- * batch splits. Keeping that protocol out of PlayContext makes ToolCall's
156
- * scalar Interface remain small without discarding the real map behaviour.
82
+ * A map Tool Result Receipt cohort is a completed-result cache over exact
83
+ * keys. It does not claim work, wait for other runs, send heartbeats, or write
84
+ * errors. Cache misses execute independently and successful writes converge
85
+ * through the store's atomic completed-result insert.
157
86
  */
158
87
  export function createToolCallReceiptCohortJob(input: {
159
88
  store: ToolCallReceiptCohortStore;
160
- sleep?: (milliseconds: number) => Promise<void>;
161
- waitDelayMs?: number;
162
89
  }): ToolCallReceiptCohortJob {
163
- const sleep = input.sleep ?? defaultSleep;
164
- const waitDelayMs = positive(input.waitDelayMs ?? 250, 'wait delay');
165
-
166
90
  return {
167
- async acquire({ owner, members, eager = false }) {
91
+ async acquire({ owner, members }) {
168
92
  const ownerRunId = required(owner.runId, 'owner run id');
169
93
  if (!Number.isInteger(owner.attempt) || owner.attempt < 0) {
170
94
  throw new Error(
@@ -178,414 +102,137 @@ export function createToolCallReceiptCohortJob(input: {
178
102
  }
179
103
 
180
104
  const groups = groupMembers(members);
105
+ const records = byKey(
106
+ await input.store.read({
107
+ resultReceiptKeys: [...groups.values()].map(
108
+ (group) => group.resultReceiptKey,
109
+ ),
110
+ }),
111
+ );
181
112
  const states = new Map<string, ToolCallReceiptCohortMemberState>();
182
- const resultDeferred = new Map<string, Deferred<ToolExecuteResult>>();
113
+ const deferred = new Map<string, Deferred<ToolExecuteResult>>();
183
114
  const owned = new Map<string, OwnedGroup>();
184
- let leaseLost: ToolCallReceiptLeaseLostError | null = null;
185
- const queuedCompletions: Array<{
186
- memberId: string;
187
- result: ToolExecuteResult;
188
- resolve(result: ToolExecuteResult): void;
189
- reject(error: unknown): void;
190
- }> = [];
191
- const queuedFailures: Array<{
192
- memberId: string;
193
- error: unknown;
194
- resolve(): void;
195
- reject(error: unknown): void;
196
- }> = [];
197
- let completionFlushScheduled = false;
198
- let failureFlushScheduled = false;
115
+ const pendingPublications: PendingPublication[] = [];
116
+ let publicationFlushScheduled = false;
199
117
 
200
- const resolveGroup = (
201
- group: Group,
202
- result: ToolExecuteResult,
203
- source: 'cache' | 'in_flight' | 'owner',
204
- ) => {
205
- const deferred = deferredFor(group, resultDeferred);
206
- deferred.resolve(result);
207
- for (const [index, member] of group.members.entries()) {
118
+ const resolveGroup = (group: Group, result: ToolExecuteResult) => {
119
+ deferredFor(group, deferred).resolve(result);
120
+ for (const member of group.members) {
208
121
  states.set(member.memberId, {
209
122
  kind: 'completed',
210
123
  result,
211
- // The physical owner receives its live dispatch result. Duplicate
212
- // map cells attached to that receipt are followers even though
213
- // the completion fanout is local to this process.
214
- source: source === 'owner' && index > 0 ? 'in_flight' : source,
124
+ source: 'owner',
215
125
  });
216
126
  }
217
127
  };
218
128
  const rejectGroup = (group: Group, error: unknown) => {
219
- const deferred = deferredFor(group, resultDeferred);
220
- deferred.reject(error);
221
- for (const member of group.members) {
222
- states.set(member.memberId, { kind: 'failed', error });
223
- }
129
+ deferredFor(group, deferred).reject(error);
224
130
  };
225
131
 
226
- const ownGroup = (group: Group, record: ToolCallReceiptRecord) => {
227
- const lease = record.lease;
228
- if (!lease || lease.ownerRunId !== ownerRunId) {
229
- throw new ToolCallReceiptLeaseLostError(group.resultReceiptKey);
132
+ for (const group of groups.values()) {
133
+ const cached = records.get(group.resultReceiptKey);
134
+ if (!group.force && cached) {
135
+ for (const member of group.members) {
136
+ states.set(member.memberId, {
137
+ kind: 'completed',
138
+ result: cached.result,
139
+ source: 'cache',
140
+ });
141
+ }
142
+ continue;
230
143
  }
231
- const ownerMember = group.members[0]!;
232
- const groupOwned: OwnedGroup = { group, lease };
144
+ const lease = {
145
+ leaseId: COMPLETED_RECEIPT_CACHE_INSERT_LEASE_ID,
146
+ ownerRunId,
147
+ };
148
+ const groupOwned = { group, lease };
233
149
  owned.set(group.resultReceiptKey, groupOwned);
150
+ const ownerMember = group.members[0]!;
234
151
  states.set(ownerMember.memberId, {
235
152
  kind: 'owned',
236
153
  resultReceiptKey: group.resultReceiptKey,
237
154
  lease,
238
- ...(record.leaseExpiresAt
239
- ? { leaseExpiresAt: record.leaseExpiresAt }
240
- : {}),
241
155
  receipts: receiptView(ownerMember.memberId, groupOwned),
242
156
  });
243
- const deferred = deferredFor(group, resultDeferred);
244
157
  for (const follower of group.members.slice(1)) {
245
158
  states.set(follower.memberId, {
246
159
  kind: 'following',
247
160
  resultReceiptKey: group.resultReceiptKey,
248
161
  ownerMemberId: ownerMember.memberId,
249
- result: deferred.promise,
162
+ result: deferredFor(group, deferred).promise,
250
163
  });
251
164
  }
252
- };
253
-
254
- const applyClaim = (
255
- group: Group,
256
- record: ToolCallReceiptRecord | undefined,
257
- source: 'cache' | 'in_flight',
258
- ) => {
259
- if (!record) return false;
260
- if (isCompleted(record)) {
261
- resolveGroup(group, record.result, source);
262
- return true;
263
- }
264
- if (record.status === 'failed') {
265
- rejectGroup(
266
- group,
267
- record.error ??
268
- new Error(
269
- `Tool Result Receipt ${group.resultReceiptKey} failed.`,
270
- ),
271
- );
272
- return true;
273
- }
274
- if (isOwned(record, ownerRunId)) {
275
- ownGroup(group, record);
276
- return true;
277
- }
278
- return false;
279
- };
280
-
281
- const claimGroups = async (targets: Group[], reclaimRunning: boolean) => {
282
- if (targets.length === 0)
283
- return new Map<string, ToolCallReceiptRecord>();
284
- const response = await input.store.claim({
285
- ownerRunId,
286
- ownerAttempt: owner.attempt,
287
- receipts: targets.map((group) => ({
288
- resultReceiptKey: group.resultReceiptKey,
289
- force: group.force,
290
- forceFailedRefresh: group.forceFailedRefresh,
291
- reclaimRunning,
292
- })),
293
- });
294
- return byKey(response);
295
- };
296
-
297
- // A forced refresh must not overlap an active foreign lease. Other
298
- // requests go straight to the atomic bulk claim, matching the existing
299
- // gateway protocol.
300
- const forceGroups = [...groups.values()].filter((group) => group.force);
301
- const forceExisting = forceGroups.length
302
- ? byKey(
303
- await input.store.read({
304
- resultReceiptKeys: forceGroups.map(
305
- (group) => group.resultReceiptKey,
306
- ),
307
- }),
308
- )
309
- : new Map<string, ToolCallReceiptRecord>();
310
- const waitGroups: Group[] = [];
311
- const initialClaimGroups: Group[] = [];
312
- for (const group of groups.values()) {
313
- const existing = forceExisting.get(group.resultReceiptKey);
314
- if (group.force && existing && isLiveLeased(existing)) {
315
- waitGroups.push(group);
316
- } else {
317
- initialClaimGroups.push(group);
318
- }
319
- }
320
- const claims = await claimGroups(initialClaimGroups, false);
321
- for (const group of initialClaimGroups) {
322
- if (!applyClaim(group, claims.get(group.resultReceiptKey), 'cache')) {
323
- waitGroups.push(group);
324
- }
325
165
  }
326
166
 
327
- const waitAttempts = new Map(
328
- waitGroups.map((group) => [
329
- group.resultReceiptKey,
330
- Math.max(
331
- 1,
332
- ...group.members.map((member) => member.waitMaxAttempts ?? 240),
333
- ),
334
- ]),
335
- );
336
- for (const group of waitGroups) {
337
- states.set(group.members[0]!.memberId, {
338
- kind: 'recovering',
339
- resultReceiptKey: group.resultReceiptKey,
340
- result: deferredFor(group, resultDeferred).promise,
341
- });
342
- for (const member of group.members.slice(1)) {
343
- states.set(member.memberId, {
344
- kind: 'recovering',
345
- resultReceiptKey: group.resultReceiptKey,
346
- result: deferredFor(group, resultDeferred).promise,
347
- });
348
- }
349
- }
350
-
351
- const settleWaitGroups = async (): Promise<void> => {
352
- const pending = new Map(
353
- waitGroups.map((group) => [group.resultReceiptKey, group]),
354
- );
167
+ const flushPublications = async (): Promise<void> => {
168
+ publicationFlushScheduled = false;
169
+ const pending = pendingPublications.splice(0);
170
+ if (pending.length === 0) return;
355
171
  try {
356
- const maxAttempts = Math.max(0, ...waitAttempts.values());
357
- for (
358
- let attempt = 0;
359
- attempt < maxAttempts && pending.size;
360
- attempt += 1
361
- ) {
362
- if (attempt > 0) await sleep(waitDelayMs);
363
- const targets = [...pending.values()].filter(
364
- (group) =>
365
- attempt < (waitAttempts.get(group.resultReceiptKey) ?? 0),
366
- );
367
- if (targets.length === 0) continue;
368
- // The context Adapter chunks this one vector sequentially. This is
369
- // the bounded hydration lane: never turn an existing map into N
370
- // per-row reads just because each member has its own recovery.
371
- const latest = byKey(
372
- await input.store.read({
373
- resultReceiptKeys: targets.map(
374
- (group) => group.resultReceiptKey,
375
- ),
376
- }),
377
- );
378
- for (const group of targets) {
379
- const record = latest.get(group.resultReceiptKey);
380
- // A forced caller cannot reuse the foreign terminal result, but
381
- // it also must not spend its whole recovery window polling a
382
- // receipt that is no longer live. Claim a fresh forced lease as
383
- // soon as the observed owner has finished (or the row vanished).
384
- // Waiting until the final attempt strands the map resolver for
385
- // the entire bounded-recovery budget after a perfectly healthy
386
- // first call completes.
387
- if (group.force) {
388
- if (!record || !isLiveLeased(record)) {
389
- const claimed = await claimGroups([group], true);
390
- if (
391
- applyClaim(
392
- group,
393
- claimed.get(group.resultReceiptKey),
394
- 'cache',
395
- )
396
- ) {
397
- pending.delete(group.resultReceiptKey);
398
- }
399
- }
400
- continue;
401
- }
402
- if (!record) continue;
403
- if (isCompleted(record)) {
404
- resolveGroup(group, record.result, 'in_flight');
405
- pending.delete(group.resultReceiptKey);
406
- } else if (record.status === 'failed') {
407
- rejectGroup(
408
- group,
409
- record.error ??
410
- new Error(
411
- `Tool Result Receipt ${group.resultReceiptKey} failed.`,
412
- ),
413
- );
414
- pending.delete(group.resultReceiptKey);
415
- }
172
+ const requested = ownedEntries(
173
+ pending.flatMap((publication) => publication.entries),
174
+ states,
175
+ owned,
176
+ );
177
+ const persisted = byKey(
178
+ await input.store.complete({
179
+ ownerRunId,
180
+ ownerAttempt: owner.attempt,
181
+ receipts: requested.map(({ group, lease, result }) => ({
182
+ resultReceiptKey: group.resultReceiptKey,
183
+ lease,
184
+ result,
185
+ })),
186
+ }),
187
+ );
188
+ const results = new Map<string, ToolExecuteResult>();
189
+ for (const entry of requested) {
190
+ // A completed-result insert is immutable: another independent
191
+ // cold miss may have published first. That does not retroactively
192
+ // turn this caller into a cache follower. It already executed, so
193
+ // return its own result and use the persisted entry only for later
194
+ // cache reads.
195
+ const result = entry.result;
196
+ owned.delete(entry.group.resultReceiptKey);
197
+ resolveGroup(entry.group, result);
198
+ for (const member of entry.group.members) {
199
+ results.set(member.memberId, result);
416
200
  }
417
201
  }
418
- if (pending.size === 0) return;
419
- const unresolved = [...pending.values()];
420
- const reclaimed = await claimGroups(unresolved, true);
421
- for (const group of unresolved) {
422
- if (
423
- applyClaim(group, reclaimed.get(group.resultReceiptKey), 'cache')
424
- ) {
425
- pending.delete(group.resultReceiptKey);
426
- continue;
427
- }
428
- const error = new ToolCallReceiptCohortWaitTimeoutError(
429
- group.resultReceiptKey,
202
+ for (const publication of pending) {
203
+ publication.resolve(
204
+ new Map(
205
+ publication.entries.flatMap((entry) => {
206
+ const result = results.get(entry.memberId);
207
+ return result ? [[entry.memberId, result] as const] : [];
208
+ }),
209
+ ),
430
210
  );
431
- rejectGroup(group, error);
432
- throw error;
433
211
  }
434
212
  } catch (error) {
435
- for (const group of pending.values()) rejectGroup(group, error);
436
- throw error;
437
- }
438
- };
439
- const settlement = settleWaitGroups();
440
- // An eager caller deliberately awaits this after independently owned
441
- // work settles. Keep a rejection observed meanwhile so a prompt adapter
442
- // read failure cannot surface as an unhandled rejection.
443
- void settlement.catch(() => undefined);
444
- if (!eager) await settlement;
445
-
446
- const assertOwned = () => {
447
- if (leaseLost) throw leaseLost;
448
- for (const group of owned.values()) {
449
- const state = states.get(group.group.members[0]!.memberId);
450
- if (
451
- !state ||
452
- state.kind !== 'owned' ||
453
- state.lease.leaseId !== group.lease.leaseId
454
- ) {
455
- throw new ToolCallReceiptLeaseLostError(
456
- group.group.resultReceiptKey,
457
- );
458
- }
213
+ for (const publication of pending) publication.reject(error);
459
214
  }
460
215
  };
461
216
 
462
- const heartbeat = async (): Promise<'active' | 'terminal'> => {
463
- if (owned.size === 0) return 'terminal';
464
- const current = [...owned.values()];
465
- const response = byKey(
466
- await input.store.heartbeat({
467
- ownerRunId,
468
- ownerAttempt: owner.attempt,
469
- receipts: current.map(({ group, lease }) => ({
470
- resultReceiptKey: group.resultReceiptKey,
471
- lease,
472
- })),
473
- }),
474
- );
475
- let active = false;
476
- for (const groupOwned of current) {
477
- const record = response.get(groupOwned.group.resultReceiptKey);
478
- if (record && isCompleted(record)) {
479
- owned.delete(groupOwned.group.resultReceiptKey);
480
- resolveGroup(groupOwned.group, record.result, 'in_flight');
481
- continue;
482
- }
483
- if (record?.status === 'failed') {
484
- owned.delete(groupOwned.group.resultReceiptKey);
485
- rejectGroup(
486
- groupOwned.group,
487
- record.error ??
488
- new Error(
489
- `Tool Result Receipt ${groupOwned.group.resultReceiptKey} failed.`,
490
- ),
491
- );
492
- continue;
493
- }
494
- if (!record || !isSameLease(record, groupOwned.lease)) {
495
- leaseLost ??= new ToolCallReceiptLeaseLostError(
496
- groupOwned.group.resultReceiptKey,
497
- );
498
- throw leaseLost;
499
- }
500
- active = true;
501
- }
502
- return active ? 'active' : 'terminal';
503
- };
504
-
505
- const complete = async (
217
+ const publish = async (
506
218
  entries: Array<{ memberId: string; result: ToolExecuteResult }>,
507
- ) => {
508
- const requested = ownedEntries(entries, states, owned);
509
- if (requested.length === 0) return new Map<string, ToolExecuteResult>();
510
- const response = byKey(
511
- await input.store.complete({
512
- ownerRunId,
513
- ownerAttempt: owner.attempt,
514
- receipts: requested.map(({ group, lease, result }) => ({
515
- resultReceiptKey: group.resultReceiptKey,
516
- lease,
517
- result,
518
- })),
519
- }),
520
- );
521
- const results = new Map<string, ToolExecuteResult>();
522
- for (const entry of requested) {
523
- const persisted = response.get(entry.group.resultReceiptKey);
524
- // Completion gateways are allowed to return a compact terminal
525
- // acknowledgement after durably storing the result. That response
526
- // is represented as a `no_result` wrapper by the adapter; it is not
527
- // the provider result and must not replace this invocation's live
528
- // value. A real no-result provider response is identical to the
529
- // submitted entry, so retaining the entry is correct there too.
530
- const result =
531
- isCompleted(persisted) && persisted.result.status !== 'no_result'
532
- ? persisted.result
533
- : entry.result;
534
- owned.delete(entry.group.resultReceiptKey);
535
- resolveGroup(entry.group, result, 'owner');
536
- for (const member of entry.group.members)
537
- results.set(member.memberId, result);
538
- }
539
- return results;
540
- };
541
-
542
- const fail = async (
543
- entries: Array<{ memberId: string; error: unknown }>,
544
- ) => {
545
- const requested = ownedEntries(entries, states, owned);
546
- if (requested.length === 0) return;
547
- await input.store.fail({
548
- ownerRunId,
549
- ownerAttempt: owner.attempt,
550
- receipts: requested.map(({ group, lease, error }) => ({
551
- resultReceiptKey: group.resultReceiptKey,
552
- lease,
553
- error,
554
- })),
555
- });
556
- for (const entry of requested) {
557
- owned.delete(entry.group.resultReceiptKey);
558
- rejectGroup(entry.group, entry.error);
559
- }
560
- };
561
-
562
- const flushCompletions = async (): Promise<void> => {
563
- completionFlushScheduled = false;
564
- const entries = queuedCompletions.splice(0);
565
- if (entries.length === 0) return;
566
- try {
567
- const results = await complete(
568
- entries.map(({ memberId, result }) => ({ memberId, result })),
569
- );
570
- for (const entry of entries) {
571
- entry.resolve(results.get(entry.memberId) ?? entry.result);
572
- }
573
- } catch (error) {
574
- for (const entry of entries) entry.reject(error);
575
- }
576
- };
577
- const flushFailures = async (): Promise<void> => {
578
- failureFlushScheduled = false;
579
- const entries = queuedFailures.splice(0);
580
- if (entries.length === 0) return;
581
- try {
582
- await fail(
583
- entries.map(({ memberId, error }) => ({ memberId, error })),
584
- );
585
- for (const entry of entries) entry.resolve();
586
- } catch (error) {
587
- for (const entry of entries) entry.reject(error);
219
+ ): Promise<Map<string, ToolExecuteResult>> => {
220
+ // Validate ownership before queuing, then coalesce writes that settle
221
+ // in this event-loop turn. This batches cache persistence only; it
222
+ // never waits for or coordinates another run's provider call.
223
+ if (ownedEntries(entries, states, owned).length === 0) {
224
+ return new Map();
588
225
  }
226
+ return await new Promise<Map<string, ToolExecuteResult>>(
227
+ (resolve, reject) => {
228
+ pendingPublications.push({ entries, resolve, reject });
229
+ if (publicationFlushScheduled) return;
230
+ publicationFlushScheduled = true;
231
+ setImmediate(() => {
232
+ void flushPublications();
233
+ });
234
+ },
235
+ );
589
236
  };
590
237
 
591
238
  function receiptView(
@@ -593,6 +240,17 @@ export function createToolCallReceiptCohortJob(input: {
593
240
  groupOwned: OwnedGroup,
594
241
  ): ToolResultReceipts {
595
242
  const { group, lease } = groupOwned;
243
+ const assert = (candidate: {
244
+ resultReceiptKey: string;
245
+ lease: ToolCallReceiptLease;
246
+ }) => {
247
+ if (
248
+ candidate.resultReceiptKey !== group.resultReceiptKey ||
249
+ !sameLease(candidate.lease, lease)
250
+ ) {
251
+ throw new ToolCallReceiptLeaseLostError(candidate.resultReceiptKey);
252
+ }
253
+ };
596
254
  return {
597
255
  async claim(candidate) {
598
256
  if (
@@ -614,86 +272,26 @@ export function createToolCallReceiptCohortJob(input: {
614
272
  candidate.resultReceiptKey,
615
273
  );
616
274
  }
617
- return await deferredFor(group, resultDeferred).promise;
275
+ return await deferredFor(group, deferred).promise;
618
276
  },
619
277
  async heartbeat(candidate) {
620
- if (
621
- candidate.resultReceiptKey !== group.resultReceiptKey ||
622
- !sameLease(candidate.lease, lease)
623
- )
624
- return 'lost';
625
- try {
626
- assertOwned();
627
- // Preserve the per-provider-admission fence from the old map
628
- // path. The cohort-wide heartbeat keeps queued work alive;
629
- // this one-member check closes the exact dispatch window.
630
- const record = byKey(
631
- await input.store.heartbeat({
632
- ownerRunId,
633
- ownerAttempt: owner.attempt,
634
- receipts: [
635
- { resultReceiptKey: group.resultReceiptKey, lease },
636
- ],
637
- }),
638
- ).get(group.resultReceiptKey);
639
- if (record && isCompleted(record)) {
640
- owned.delete(group.resultReceiptKey);
641
- resolveGroup(group, record.result, 'in_flight');
642
- return 'completed';
643
- }
644
- if (!record || !isSameLease(record, lease)) return 'lost';
645
- return 'active';
646
- } catch (error) {
647
- if (error instanceof ToolCallReceiptLeaseLostError) return 'lost';
648
- throw error;
649
- }
278
+ assert(candidate);
279
+ return owned.has(group.resultReceiptKey) ? 'active' : 'completed';
650
280
  },
651
281
  async complete(candidate) {
652
- if (
653
- candidate.resultReceiptKey !== group.resultReceiptKey ||
654
- !sameLease(candidate.lease, lease)
655
- ) {
656
- throw new ToolCallReceiptLeaseLostError(
657
- candidate.resultReceiptKey,
658
- );
659
- }
660
- const result = await new Promise<ToolExecuteResult>(
661
- (resolve, reject) => {
662
- queuedCompletions.push({
663
- memberId,
664
- result: candidate.result,
665
- resolve,
666
- reject,
667
- });
668
- if (!completionFlushScheduled) {
669
- completionFlushScheduled = true;
670
- setTimeout(() => void flushCompletions(), 0);
671
- }
672
- },
673
- );
674
- return { kind: 'stored', result };
282
+ assert(candidate);
283
+ const results = await publish([
284
+ { memberId, result: candidate.result },
285
+ ]);
286
+ return {
287
+ kind: 'stored',
288
+ result: results.get(memberId) ?? candidate.result,
289
+ };
675
290
  },
676
291
  async fail(candidate) {
677
- if (
678
- candidate.resultReceiptKey !== group.resultReceiptKey ||
679
- !sameLease(candidate.lease, lease)
680
- ) {
681
- throw new ToolCallReceiptLeaseLostError(
682
- candidate.resultReceiptKey,
683
- );
684
- }
685
- await new Promise<void>((resolve, reject) => {
686
- queuedFailures.push({
687
- memberId,
688
- error: candidate.error,
689
- resolve,
690
- reject,
691
- });
692
- if (!failureFlushScheduled) {
693
- failureFlushScheduled = true;
694
- setTimeout(() => void flushFailures(), 0);
695
- }
696
- });
292
+ assert(candidate);
293
+ owned.delete(group.resultReceiptKey);
294
+ rejectGroup(group, candidate.error);
697
295
  },
698
296
  };
699
297
  }
@@ -701,33 +299,35 @@ export function createToolCallReceiptCohortJob(input: {
701
299
  return {
702
300
  member(memberId) {
703
301
  const state = states.get(memberId);
704
- if (!state)
302
+ if (!state) {
705
303
  throw new Error(
706
304
  `Unknown Tool Call Receipt Cohort member ${memberId}.`,
707
305
  );
306
+ }
708
307
  return state;
709
308
  },
710
- complete,
711
- fail,
712
- heartbeat,
713
- startHeartbeat({ intervalMs, onLeaseLost, onTransientFailure }) {
714
- const supervisor = createRuntimeReceiptHeartbeatSupervisor({
715
- intervalMs: positive(intervalMs, 'heartbeat interval'),
716
- heartbeat,
717
- isLeaseLost: (error) =>
718
- error instanceof ToolCallReceiptLeaseLostError,
719
- onLeaseLost: (error) => {
720
- leaseLost ??= error as ToolCallReceiptLeaseLostError;
721
- onLeaseLost(leaseLost);
722
- },
723
- onTransientFailure,
724
- });
725
- supervisor.start();
726
- return { stop: () => supervisor.stop(), assertOwned };
309
+ complete: publish,
310
+ async fail(entries) {
311
+ for (const entry of entries) {
312
+ const state = states.get(entry.memberId);
313
+ if (!state || state.kind !== 'owned') {
314
+ throw new ToolCallReceiptLeaseLostError(entry.memberId);
315
+ }
316
+ const groupOwned = owned.get(state.resultReceiptKey);
317
+ if (!groupOwned) {
318
+ throw new ToolCallReceiptLeaseLostError(state.resultReceiptKey);
319
+ }
320
+ owned.delete(state.resultReceiptKey);
321
+ rejectGroup(groupOwned.group, entry.error);
322
+ }
323
+ },
324
+ async heartbeat() {
325
+ return owned.size === 0 ? 'terminal' : 'active';
727
326
  },
728
- async settle() {
729
- await settlement;
327
+ startHeartbeat() {
328
+ return { stop: () => undefined, assertOwned: () => undefined };
730
329
  },
330
+ async settle() {},
731
331
  };
732
332
  },
733
333
  };
@@ -737,7 +337,6 @@ type Group = {
737
337
  resultReceiptKey: string;
738
338
  members: ToolCallReceiptCohortMember[];
739
339
  force: boolean;
740
- forceFailedRefresh: boolean;
741
340
  };
742
341
 
743
342
  type OwnedGroup = { group: Group; lease: ToolCallReceiptLease };
@@ -748,6 +347,12 @@ type Deferred<T> = {
748
347
  reject(error: unknown): void;
749
348
  };
750
349
 
350
+ type PendingPublication = {
351
+ entries: Array<{ memberId: string; result: ToolExecuteResult }>;
352
+ resolve(value: Map<string, ToolExecuteResult>): void;
353
+ reject(error: unknown): void;
354
+ };
355
+
751
356
  function groupMembers(
752
357
  members: ToolCallReceiptCohortMember[],
753
358
  ): Map<string, Group> {
@@ -755,8 +360,9 @@ function groupMembers(
755
360
  const memberIds = new Set<string>();
756
361
  for (const member of members) {
757
362
  const memberId = required(member.memberId, 'member id');
758
- if (memberIds.has(memberId))
363
+ if (memberIds.has(memberId)) {
759
364
  throw new Error(`Duplicate Tool Call Receipt Cohort member ${memberId}.`);
365
+ }
760
366
  memberIds.add(memberId);
761
367
  const resultReceiptKey = required(
762
368
  member.resultReceiptKey,
@@ -766,18 +372,11 @@ function groupMembers(
766
372
  resultReceiptKey,
767
373
  members: [],
768
374
  force: false,
769
- forceFailedRefresh: false,
770
375
  };
771
376
  group.members.push({ ...member, memberId, resultReceiptKey });
772
377
  group.force ||= member.force === true;
773
- group.forceFailedRefresh ||= member.forceFailedRefresh === true;
774
378
  groups.set(resultReceiptKey, group);
775
379
  }
776
- for (const group of groups.values()) {
777
- // Full force dominates failed-only refresh for every duplicate member of
778
- // the same content-addressed receipt, just as the current map grouping.
779
- if (group.force) group.forceFailedRefresh = false;
780
- }
781
380
  return groups;
782
381
  }
783
382
 
@@ -795,8 +394,6 @@ function deferredFor(
795
394
  reject = rejectPromise;
796
395
  },
797
396
  );
798
- // A receipt can fail before a same-run follower attaches. Do not create an
799
- // unhandled rejection while preserving the rejection for real followers.
800
397
  void promise.catch(() => undefined);
801
398
  value = { promise, resolve, reject };
802
399
  deferred.set(group.resultReceiptKey, value);
@@ -812,20 +409,12 @@ function ownedEntries<T extends { memberId: string }>(
812
409
  for (const entry of entries) {
813
410
  const state = states.get(entry.memberId);
814
411
  if (!state || state.kind !== 'owned') {
815
- throw new Error(
816
- `Tool Call Receipt Cohort member ${entry.memberId} does not own a receipt.`,
817
- );
412
+ throw new ToolCallReceiptLeaseLostError(entry.memberId);
818
413
  }
819
414
  const groupOwned = owned.get(state.resultReceiptKey);
820
415
  if (!groupOwned || !sameLease(groupOwned.lease, state.lease)) {
821
416
  throw new ToolCallReceiptLeaseLostError(state.resultReceiptKey);
822
417
  }
823
- const existing = byKey.get(groupOwned.group.resultReceiptKey);
824
- if (existing && existing.memberId !== entry.memberId) {
825
- throw new Error(
826
- `Tool Call Receipt Cohort received two terminal outcomes for ${groupOwned.group.resultReceiptKey}.`,
827
- );
828
- }
829
418
  byKey.set(groupOwned.group.resultReceiptKey, { ...entry, ...groupOwned });
830
419
  }
831
420
  return [...byKey.values()];
@@ -834,49 +423,7 @@ function ownedEntries<T extends { memberId: string }>(
834
423
  function byKey(
835
424
  records: ToolCallReceiptRecord[],
836
425
  ): Map<string, ToolCallReceiptRecord> {
837
- const result = new Map<string, ToolCallReceiptRecord>();
838
- for (const record of records) result.set(record.resultReceiptKey, record);
839
- return result;
840
- }
841
-
842
- function isCompleted(
843
- record: ToolCallReceiptRecord | undefined,
844
- ): record is ToolCallReceiptRecord & { result: ToolExecuteResult } {
845
- if (!record) return false;
846
- return (
847
- (record.status === 'completed' || record.status === 'skipped') &&
848
- record.result !== undefined
849
- );
850
- }
851
-
852
- function isOwned(record: ToolCallReceiptRecord, ownerRunId: string): boolean {
853
- return (
854
- record.claimState !== 'existing' &&
855
- Boolean(record.lease) &&
856
- record.lease?.ownerRunId === ownerRunId &&
857
- (record.status === 'queued' ||
858
- record.status === 'pending' ||
859
- record.status === 'running')
860
- );
861
- }
862
-
863
- function isLiveLeased(record: ToolCallReceiptRecord): boolean {
864
- if (
865
- record.status !== 'queued' &&
866
- record.status !== 'pending' &&
867
- record.status !== 'running'
868
- )
869
- return false;
870
- if (!record.lease) return false;
871
- const expiresAt = Date.parse(record.leaseExpiresAt ?? '');
872
- return !Number.isFinite(expiresAt) || expiresAt > Date.now();
873
- }
874
-
875
- function isSameLease(
876
- record: ToolCallReceiptRecord,
877
- lease: ToolCallReceiptLease,
878
- ): boolean {
879
- return Boolean(record.lease) && sameLease(record.lease!, lease);
426
+ return new Map(records.map((record) => [record.resultReceiptKey, record]));
880
427
  }
881
428
 
882
429
  function sameLease(
@@ -888,17 +435,8 @@ function sameLease(
888
435
 
889
436
  function required(value: string, name: string): string {
890
437
  const normalized = value?.trim();
891
- if (!normalized)
438
+ if (!normalized) {
892
439
  throw new Error(`Tool Call Receipt Cohort requires a ${name}.`);
440
+ }
893
441
  return normalized;
894
442
  }
895
-
896
- function positive(value: number, name: string): number {
897
- if (!Number.isFinite(value) || value <= 0)
898
- throw new Error(`Tool Call Receipt Cohort ${name} must be positive.`);
899
- return Math.floor(value);
900
- }
901
-
902
- async function defaultSleep(milliseconds: number): Promise<void> {
903
- await new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
904
- }