@agentunion/fastaun 0.5.21 → 0.5.23

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 (75) hide show
  1. package/CHANGELOG.md +58 -1
  2. package/_packed_docs/CHANGELOG.md +58 -1
  3. package/_packed_docs/INDEX.md +469 -453
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +169 -164
  5. package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +307 -67
  6. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +41 -15
  7. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +5 -5
  8. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +30 -8
  9. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +669 -666
  10. package/_packed_docs/sdk/0.5.22-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +212 -0
  11. package/_packed_docs/sdk/0.5.22-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +199 -0
  12. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +16 -0
  13. package/_packed_docs/sdk/09-group-rpc-manual.md +10 -0
  14. package/_packed_docs/sdk/09-storage-rpc-manual.md +64 -7
  15. package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +3 -1
  16. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +2 -0
  17. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +138 -134
  18. package/_packed_docs/sdk/INDEX.md +255 -239
  19. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +939 -930
  20. package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +312 -363
  21. package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +322 -553
  22. package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +4 -4
  23. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +484 -480
  24. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +190 -97
  25. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +158 -127
  26. package/dist/agent-md.d.ts +16 -2
  27. package/dist/agent-md.js +59 -23
  28. package/dist/agent-md.js.map +1 -1
  29. package/dist/aid-store.d.ts +1 -0
  30. package/dist/aid-store.js +43 -8
  31. package/dist/aid-store.js.map +1 -1
  32. package/dist/auth.d.ts +7 -0
  33. package/dist/auth.js +222 -70
  34. package/dist/auth.js.map +1 -1
  35. package/dist/client/delivery.d.ts +28 -0
  36. package/dist/client/delivery.js +399 -44
  37. package/dist/client/delivery.js.map +1 -1
  38. package/dist/client/group-state.js +3 -0
  39. package/dist/client/group-state.js.map +1 -1
  40. package/dist/client/rpc-pipeline.js +28 -2
  41. package/dist/client/rpc-pipeline.js.map +1 -1
  42. package/dist/client/v2-e2ee.js +109 -39
  43. package/dist/client/v2-e2ee.js.map +1 -1
  44. package/dist/client.d.ts +3 -0
  45. package/dist/client.js +114 -26
  46. package/dist/client.js.map +1 -1
  47. package/dist/group-fs.d.ts +1 -0
  48. package/dist/group-fs.js +37 -19
  49. package/dist/group-fs.js.map +1 -1
  50. package/dist/org-protocol.d.ts +11 -0
  51. package/dist/org-protocol.js +154 -19
  52. package/dist/org-protocol.js.map +1 -1
  53. package/dist/ownership-v21.d.ts +21 -3
  54. package/dist/ownership-v21.js +135 -37
  55. package/dist/ownership-v21.js.map +1 -1
  56. package/dist/ownership-workflow.d.ts +7 -2
  57. package/dist/ownership-workflow.js +173 -17
  58. package/dist/ownership-workflow.js.map +1 -1
  59. package/dist/storage/lowlevel.d.ts +6 -0
  60. package/dist/storage/lowlevel.js +24 -7
  61. package/dist/storage/lowlevel.js.map +1 -1
  62. package/dist/storage/read-cache.d.ts +70 -0
  63. package/dist/storage/read-cache.js +625 -0
  64. package/dist/storage/read-cache.js.map +1 -0
  65. package/dist/storage/vfs.d.ts +2 -0
  66. package/dist/storage/vfs.js +50 -15
  67. package/dist/storage/vfs.js.map +1 -1
  68. package/dist/tools/cross-sdk-agent.d.ts +21 -1
  69. package/dist/tools/cross-sdk-agent.js +301 -19
  70. package/dist/tools/cross-sdk-agent.js.map +1 -1
  71. package/dist/transport.js +6 -2
  72. package/dist/transport.js.map +1 -1
  73. package/dist/version.d.ts +1 -1
  74. package/dist/version.js +1 -1
  75. package/package.json +1 -1
@@ -1306,6 +1306,7 @@ export class V2E2EECoordinator {
1306
1306
  const client = this.client;
1307
1307
  const generation = Number(client._v2RuntimeGeneration ?? 0);
1308
1308
  const inlineGeneration = client._delivery.captureInlineAckGeneration?.();
1309
+ const pullVersion = opts.peerPullVersion ?? client._delivery.capturePeerTailVersion(senderAid);
1309
1310
  await client._ensureV2SessionReady('message.pull');
1310
1311
  this.ensureDeliveryCurrent(client._delivery.peerNamespace(senderAid), generation, inlineGeneration);
1311
1312
  const ns = await client._delivery.initializePeer(senderAid);
@@ -1313,18 +1314,20 @@ export class V2E2EECoordinator {
1313
1314
  const limit = Number(opts.limit ?? _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize);
1314
1315
  if (!Number.isSafeInteger(limit) || limit < 1 || limit > 200)
1315
1316
  throw new ValidationError('peer limit must be between 1 and 200');
1316
- const mode = opts.window_mode === 'tail' ? 'tail' : 'forward';
1317
- const source = mode === 'tail' ? 'tail' : 'pull';
1317
+ let mode = opts.window_mode === 'tail' ? 'tail' : 'forward';
1318
+ let source = mode === 'tail' ? 'tail' : 'pull';
1318
1319
  if (mode === 'tail' && (opts.force === true || 'ack_up_to_seq' in opts))
1319
1320
  throw new ValidationError('Tail does not accept force or ACK');
1320
1321
  const budget = opts.budget ?? { remaining: Math.max(1, Number(opts.max_pages ?? 100)) };
1321
1322
  let after = opts.after_seq === undefined ? client._seqTracker.getContiguousSeq(ns) : strictWindowSeq(opts.after_seq, 'after_seq');
1322
- if (opts.force !== true && after > client._seqTracker.getContiguousSeq(ns))
1323
+ if (mode !== 'tail' && opts.force !== true && after > client._seqTracker.getContiguousSeq(ns))
1323
1324
  throw new ValidationError('after_seq cannot exceed the peer delivery cursor');
1324
1325
  let volatileCursor = String(opts.after_volatile_cursor ?? client._delivery.peerVolatilePullCursor(senderAid));
1325
1326
  const decoded = [];
1326
1327
  let complete = false;
1327
1328
  let head = after;
1329
+ let tailVolatileHasMore;
1330
+ let tailServerAck = null;
1328
1331
  let pages = 0;
1329
1332
  let durableAck = 0;
1330
1333
  let initializedAck = false;
@@ -1335,6 +1338,7 @@ export class V2E2EECoordinator {
1335
1338
  };
1336
1339
  const prefetched = [];
1337
1340
  const stopping = new AbortController();
1341
+ const canPull = () => !opts.background || client._delivery.hasP2pApplicationSubscription();
1338
1342
  const validatePage = (response, requestAfter, committedAck, preparing = false) => {
1339
1343
  this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1340
1344
  this.validatePeerResponse(response, senderAid);
@@ -1350,8 +1354,12 @@ export class V2E2EECoordinator {
1350
1354
  if (response.window_mode !== 'tail')
1351
1355
  throw new ValidationError('peer Tail response mode mismatch');
1352
1356
  start = strictWindowSeq(response.window_start_seq, 'window_start_seq');
1353
- if (start > end || end !== pageHead || (end > requestAfter && start < requestAfter + 1))
1357
+ if (volatile.length > 0 || start > end || end !== pageHead || (pageHead <= requestAfter
1358
+ ? start !== pageHead || persistent.length > 0
1359
+ : start <= requestAfter))
1354
1360
  throw new ValidationError('invalid peer Tail proof');
1361
+ if (response.volatile_has_more !== undefined && typeof response.volatile_has_more !== 'boolean')
1362
+ throw new ValidationError('invalid peer Tail volatile proof');
1355
1363
  }
1356
1364
  else {
1357
1365
  start = strictWindowSeq(response.scan_after_seq, 'scan_after_seq');
@@ -1371,8 +1379,12 @@ export class V2E2EECoordinator {
1371
1379
  throw new ValidationError('peer message is outside proof or sender');
1372
1380
  previous = seq;
1373
1381
  }
1374
- if (mode === 'forward' && opts.force !== true)
1375
- confirmAck(safeNonNegativeSeq(response.server_ack_seq) ?? 0);
1382
+ if (mode === 'forward' && opts.force !== true) {
1383
+ const serverAck = safeNonNegativeSeq(response.server_ack_seq);
1384
+ if (serverAck !== null)
1385
+ client._delivery.observePeerServerAck(ns, serverAck);
1386
+ confirmAck(serverAck ?? 0);
1387
+ }
1376
1388
  return { persistent, volatile, end, pageHead, start };
1377
1389
  };
1378
1390
  const decodeRows = async (rows) => {
@@ -1397,28 +1409,38 @@ export class V2E2EECoordinator {
1397
1409
  };
1398
1410
  const fetchPage = async (requestAfter, requestCursor) => {
1399
1411
  const key = `${ns}|mode=${mode}|after=${requestAfter}|volatile=${requestCursor}|force=${Boolean(opts.force)}|limit=${limit}`;
1400
- const request = (cursor) => client._runPullSerialized(key, () => client._callRawV2Rpc('message.v2.pull', {
1401
- cursor_scope: 'peer', sender_aid: senderAid, device_id: client._deviceId, slot_id: client._slotId,
1402
- after_seq: requestAfter, limit,
1403
- ...(mode === 'forward' && opts.force !== true && durableAck > 0 ? { ack_up_to_seq: durableAck } : {}),
1404
- ...(mode === 'tail' ? { window_mode: 'tail' } : {}),
1405
- ...(opts.force === true ? { force: true } : {}),
1406
- ...(cursor ? { after_volatile_cursor: cursor } : {}),
1407
- ...(opts.background ? { _rpc_background: true } : { _rpc_foreground: true }),
1408
- }, key), Boolean(opts.background));
1412
+ const request = (cursor) => {
1413
+ const operation = async () => {
1414
+ if (!canPull()) {
1415
+ reservation?.release();
1416
+ return null;
1417
+ }
1418
+ return { response: await client._callRawV2Rpc('message.v2.pull', {
1419
+ cursor_scope: 'peer', sender_aid: senderAid, device_id: client._deviceId, slot_id: client._slotId,
1420
+ after_seq: requestAfter, limit,
1421
+ ...(mode === 'forward' && opts.force !== true && durableAck > 0 ? { ack_up_to_seq: durableAck } : {}),
1422
+ ...(mode === 'tail' ? { window_mode: 'tail' } : {}),
1423
+ ...(opts.force === true ? { force: true } : {}),
1424
+ ...(cursor ? { after_volatile_cursor: cursor } : {}),
1425
+ ...(opts.background ? { _rpc_background: true } : { _rpc_foreground: true }),
1426
+ }, key), reservation };
1427
+ };
1428
+ const schedule = (attempt) => client._runPullSerialized(key, attempt, Boolean(opts.background));
1429
+ return client._delivery.runPeerPullAttempt?.(ns, operation, schedule) ?? schedule(operation);
1430
+ };
1409
1431
  const reservation = await client._dispatcher?._reserveMessageCapacity?.(limit, stopping.signal);
1410
1432
  try {
1411
1433
  if (stopping.signal.aborted)
1412
1434
  throw new StateError('pull invalidated');
1413
1435
  try {
1414
- return { response: await request(requestCursor), reservation };
1436
+ return await request(requestCursor);
1415
1437
  }
1416
1438
  catch (error) {
1417
1439
  this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1418
1440
  if (!requestCursor || !String(error instanceof Error ? error.message : error).toLowerCase().includes('volatile cursor epoch mismatch'))
1419
1441
  throw error;
1420
1442
  client._delivery.setPeerVolatilePullCursor(senderAid, '');
1421
- return { response: await request(''), reservation };
1443
+ return await request('');
1422
1444
  }
1423
1445
  }
1424
1446
  catch (error) {
@@ -1430,7 +1452,7 @@ export class V2E2EECoordinator {
1430
1452
  const existing = prefetched.find((page) => page.after === requestAfter && page.cursor === cursor);
1431
1453
  if (existing)
1432
1454
  return existing;
1433
- if (prefetched.length >= 2 || budget.remaining <= 0 || stopping.signal.aborted)
1455
+ if (prefetched.length >= 2 || budget.remaining <= 0 || stopping.signal.aborted || !canPull())
1434
1456
  return undefined;
1435
1457
  budget.remaining -= 1;
1436
1458
  const page = { after: requestAfter, cursor, response: fetchPage(requestAfter, cursor) };
@@ -1442,6 +1464,8 @@ export class V2E2EECoordinator {
1442
1464
  if (page.prepared)
1443
1465
  return;
1444
1466
  page.prepared = page.response.then(async (fetched) => {
1467
+ if (!fetched)
1468
+ return null;
1445
1469
  try {
1446
1470
  const proof = validatePage(fetched.response, page.after, durableAck, true);
1447
1471
  const handlers = client._delivery.snapshotApplicationHandlers?.();
@@ -1461,6 +1485,8 @@ export class V2E2EECoordinator {
1461
1485
  let failed = false;
1462
1486
  try {
1463
1487
  while (budget.remaining > 0 || prefetched.length > 0) {
1488
+ if (prefetched.length === 0 && !canPull())
1489
+ break;
1464
1490
  const cached = prefetched.shift();
1465
1491
  if (!cached)
1466
1492
  budget.remaining -= 1;
@@ -1473,11 +1499,19 @@ export class V2E2EECoordinator {
1473
1499
  durableAck = committedAck;
1474
1500
  initializedAck = true;
1475
1501
  }
1502
+ if (!cached && mode === 'tail' && opts.autoTail
1503
+ && !client._delivery.shouldTailPeer(ns, opts.autoTail.head, limit, opts.autoTail.forwardNeed)) {
1504
+ mode = 'forward';
1505
+ source = 'pull';
1506
+ opts.autoTail.forward = true;
1507
+ }
1476
1508
  if (!cached && mode === 'forward' && opts.force !== true)
1477
1509
  requestedAfter = Math.max(requestedAfter, committedAck);
1478
1510
  if (!cached)
1479
1511
  this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1480
1512
  const fetched = await (cached ? cached.prepared ?? cached.response : fetchPage(requestedAfter, requestedVolatile));
1513
+ if (!fetched)
1514
+ return null;
1481
1515
  const { response, reservation } = fetched;
1482
1516
  try {
1483
1517
  this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
@@ -1518,7 +1552,8 @@ export class V2E2EECoordinator {
1518
1552
  const before = client._seqTracker.snapshotNamespace(ns);
1519
1553
  try {
1520
1554
  if (mode === 'tail') {
1521
- client._seqTracker.commitTailWindow(ns, { windowStartSeq: start, headSeq: pageHead, coveredThroughSeq: end, pageLimit: limit, sparse: true });
1555
+ if (pageHead > requestedAfter)
1556
+ client._seqTracker.commitTailWindow(ns, { windowStartSeq: start, headSeq: pageHead, coveredThroughSeq: end, pageLimit: limit, sparse: true });
1522
1557
  }
1523
1558
  else if (opts.force !== true) {
1524
1559
  client._seqTracker.onPullResult(ns, persistent, requestedAfter, end);
@@ -1551,10 +1586,18 @@ export class V2E2EECoordinator {
1551
1586
  reservation?.release();
1552
1587
  }
1553
1588
  });
1589
+ if (!page)
1590
+ break;
1554
1591
  this.ensureDeliveryCurrent(ns, generation, inlineGeneration);
1555
1592
  if (opts.retainMessages !== false)
1556
1593
  decoded.push(...page.messages);
1557
1594
  head = page.head;
1595
+ if (mode === 'tail') {
1596
+ tailVolatileHasMore = page.response.volatile_has_more;
1597
+ tailServerAck = safeNonNegativeSeq(page.response.server_ack_seq);
1598
+ if (tailServerAck !== null)
1599
+ client._delivery.observePeerServerAck(ns, tailServerAck);
1600
+ }
1558
1601
  volatileCursor = client._delivery.peerVolatilePullCursor(senderAid);
1559
1602
  const more = page.response.persistent_has_more === true || page.response.volatile_has_more === true || page.response.has_more === true;
1560
1603
  complete = !more;
@@ -1573,7 +1616,7 @@ export class V2E2EECoordinator {
1573
1616
  stopping.abort();
1574
1617
  for (const pending of prefetched) {
1575
1618
  try {
1576
- (await (pending.prepared ?? pending.response)).reservation?.release();
1619
+ (await (pending.prepared ?? pending.response))?.reservation?.release();
1577
1620
  }
1578
1621
  catch { }
1579
1622
  }
@@ -1594,10 +1637,17 @@ export class V2E2EECoordinator {
1594
1637
  }
1595
1638
  }
1596
1639
  const ack = client._seqTracker.getContiguousSeq(ns);
1597
- if (!opts.background && opts.force !== true && (!complete || (mode === 'tail' && ack < head)))
1640
+ if (mode === 'tail')
1641
+ complete = ack >= head && durableAck >= head && tailVolatileHasMore === false
1642
+ && tailServerAck !== null && tailServerAck >= durableAck && this.pendingForwardAck(ns, durableAck) === 0;
1643
+ if (opts.force !== true && complete)
1644
+ complete = client._delivery.isPeerTailCurrent(senderAid, pullVersion, Math.min(ack, durableAck));
1645
+ if (!opts.background && opts.force !== true && !complete)
1598
1646
  client._delivery.schedulePeerRecovery(senderAid, head, true);
1599
- return { sender_aid: senderAid, messages: decoded, complete: mode === 'tail' ? ack >= head : complete,
1600
- ack_seq: ack, head_seq: head, pages };
1647
+ return { sender_aid: senderAid, messages: decoded, complete,
1648
+ ack_seq: ack, head_seq: head, pages,
1649
+ ...(mode === 'tail' ? { ...(tailVolatileHasMore === undefined ? {} : { volatile_has_more: tailVolatileHasMore }),
1650
+ ...(tailServerAck === null ? {} : { server_ack_seq: tailServerAck }), pending_ack_seq: this.pendingForwardAck(ns, durableAck) } : {}) };
1601
1651
  }
1602
1652
  validatePeerResponse(response, senderAid) {
1603
1653
  const client = this.client;
@@ -1626,6 +1676,8 @@ export class V2E2EECoordinator {
1626
1676
  const actual = safeNonNegativeSeq(result.peer_ack_seq ?? result.effective_ack_seq ?? result.up_to_seq);
1627
1677
  if (seq > 0 && (actual === null || actual < seq))
1628
1678
  throw new E2EEError('peer ACK watermark is below requested');
1679
+ if (actual !== null)
1680
+ client._delivery.observePeerServerAck(ns, actual);
1629
1681
  client._delivery.peerAckChanged();
1630
1682
  return result;
1631
1683
  }
@@ -1669,12 +1721,28 @@ export class V2E2EECoordinator {
1669
1721
  const afterSeq = strictWindowSeq(params.after_seq ?? 0, 'after_seq');
1670
1722
  const limit = strictWindowLimit(params.limit ?? V2_PULL_DEFAULT_PAGE_LIMIT);
1671
1723
  const ns = client._aid ? `p2p:${client._aid}` : '';
1724
+ const volatileCursor = String(params.after_volatile_cursor ?? client._delivery.volatilePullCursor?.(ns) ?? '');
1672
1725
  if (ns)
1673
1726
  client._delivery.syncStarted(ns);
1674
- const pullGateKey = pullGateKeyForClient(client, 'message.v2.pull', {
1675
- window_mode: 'tail', after_seq: afterSeq, limit,
1676
- }, `${ns}|tail|after=${afterSeq}|limit=${limit}`);
1677
- const result = await client._callRawV2Rpc('message.v2.pull', { window_mode: 'tail', after_seq: afterSeq, limit, _rpc_foreground: true }, pullGateKey);
1727
+ const request = (cursor) => {
1728
+ const tailParams = { window_mode: 'tail', after_seq: afterSeq, limit,
1729
+ ...(cursor ? { after_volatile_cursor: cursor } : {}) };
1730
+ const pullGateKey = pullGateKeyForClient(client, 'message.v2.pull', tailParams, `${ns}|tail|after=${afterSeq}|limit=${limit}${cursor ? `|volatile=${cursor}` : ''}`);
1731
+ return client._callRawV2Rpc('message.v2.pull', { ...tailParams, _rpc_foreground: true }, pullGateKey);
1732
+ };
1733
+ let result;
1734
+ try {
1735
+ result = await request(volatileCursor);
1736
+ }
1737
+ catch (error) {
1738
+ this.ensureDeliveryCurrent(ns, generation);
1739
+ if (!volatileCursor || !String(error instanceof Error ? error.message : error).toLowerCase().includes('volatile cursor epoch mismatch'))
1740
+ throw error;
1741
+ client._delivery.resetVolatilePullCursor?.();
1742
+ result = await request('');
1743
+ }
1744
+ if (Array.isArray(result?.messages) && result.messages.some((row) => row?.storage === 'volatile'))
1745
+ throw new ValidationError('Tail cannot return volatile messages');
1678
1746
  const page = validateTailPage(result, afterSeq, limit);
1679
1747
  const decoded = [];
1680
1748
  await this.withApplicationPage(ns, 'tail', async () => {
@@ -1687,12 +1755,13 @@ export class V2E2EECoordinator {
1687
1755
  });
1688
1756
  this.ensureDeliveryCurrent(ns, generation);
1689
1757
  if (ns) {
1690
- client._seqTracker.commitTailWindow(ns, {
1691
- windowStartSeq: page.windowStart,
1692
- headSeq: page.head,
1693
- coveredThroughSeq: page.head,
1694
- pageLimit: limit,
1695
- });
1758
+ if (page.head > afterSeq)
1759
+ client._seqTracker.commitTailWindow(ns, {
1760
+ windowStartSeq: page.windowStart,
1761
+ headSeq: page.head,
1762
+ coveredThroughSeq: page.head,
1763
+ pageLimit: limit,
1764
+ });
1696
1765
  client._persistSeq(ns);
1697
1766
  await client._saveSeqTrackerState?.();
1698
1767
  this.ensureDeliveryCurrent(ns, generation);
@@ -2659,12 +2728,13 @@ export class V2E2EECoordinator {
2659
2728
  client._delivery.rememberCommittedSeqState?.(ns);
2660
2729
  const snapshot = client._seqTracker.snapshotNamespace?.(ns) ?? null;
2661
2730
  try {
2662
- client._seqTracker.commitTailWindow(ns, {
2663
- windowStartSeq: page.windowStart,
2664
- headSeq: page.head,
2665
- coveredThroughSeq: page.head,
2666
- pageLimit: limit,
2667
- });
2731
+ if (page.head > afterSeq)
2732
+ client._seqTracker.commitTailWindow(ns, {
2733
+ windowStartSeq: page.windowStart,
2734
+ headSeq: page.head,
2735
+ coveredThroughSeq: page.head,
2736
+ pageLimit: limit,
2737
+ });
2668
2738
  await client._commitSeqTrackerState(ns);
2669
2739
  if (client._delivery.isSeqNamespaceGenerationCurrent?.(ns, namespaceGeneration) === false)
2670
2740
  throw new Error('pull invalidated');