LibreChat/packages/data-schemas/src/methods/triggerDelivery.spec.ts
Danny Avila 52fa88fc54
📬 feat: Serialize Bound Actor Event Mailboxes (#15260)
* feat: serialize bound actor event mailboxes

* test: harden actor mailbox batch ordering

* fix: treat batch roots as mailbox authority

* test: pin mailbox replay semantics

* fix: preserve mailbox authority through settlement
2026-08-26 10:02:47 -04:00

1939 lines
67 KiB
TypeScript

import mongoose from 'mongoose';
import { MongoMemoryServer } from 'mongodb-memory-server';
import type { Model } from 'mongoose';
import type {
AgentTriggerDeliveryFailure,
IAgentTriggerDeliveryDocument,
IAgentTriggerLaneSequenceDocument,
IAgentTriggerUserPurgeDocument,
} from '~/types/triggerDelivery';
import type { IUser } from '~/types/user';
import {
AgentTriggerDeliveryConflictError,
createAgentTriggerDeliveryMethods,
type AgentTriggerDeliveryMethods,
} from './triggerDelivery';
import { createAgentTriggerLaneSequenceModel } from '../models/triggerLaneSequence';
import { createAgentTriggerUserPurgeModel } from '../models/triggerUserPurge';
import { createAgentTriggerDeliveryModel } from '../models/triggerDelivery';
import { createUserModel } from '../models/user';
jest.mock('~/config/winston', () => ({
error: jest.fn(),
warn: jest.fn(),
info: jest.fn(),
debug: jest.fn(),
}));
const DB_SETUP_TIMEOUT_MS = 60_000;
const START = new Date('2026-08-17T12:00:00.000Z');
let mongoServer: MongoMemoryServer;
let Delivery: Model<IAgentTriggerDeliveryDocument>;
let LaneSequence: Model<IAgentTriggerLaneSequenceDocument>;
let UserPurge: Model<IAgentTriggerUserPurgeDocument>;
let User: Model<IUser>;
let methods: AgentTriggerDeliveryMethods;
let counter = 0;
beforeAll(async () => {
mongoServer = await MongoMemoryServer.create();
await mongoose.connect(mongoServer.getUri());
Delivery = createAgentTriggerDeliveryModel(mongoose);
LaneSequence = createAgentTriggerLaneSequenceModel(mongoose);
UserPurge = createAgentTriggerUserPurgeModel(mongoose);
User = createUserModel(mongoose);
await Promise.all([Delivery.init(), LaneSequence.init(), UserPurge.init(), User.init()]);
methods = createAgentTriggerDeliveryMethods(mongoose);
}, DB_SETUP_TIMEOUT_MS);
afterAll(async () => {
await mongoose.disconnect();
await mongoServer.stop();
}, DB_SETUP_TIMEOUT_MS);
beforeEach(async () => {
await Promise.all([
Delivery.deleteMany({}),
LaneSequence.deleteMany({}),
UserPurge.deleteMany({}),
User.deleteMany({}),
]);
});
function enqueueInput(
overrides: Partial<Parameters<typeof methods.enqueueAgentTriggerDelivery>[0]> = {},
) {
counter += 1;
return {
deliveryKey: `trigger_${counter}`,
fingerprint: `fingerprint_${counter}`,
orderingKey: 'ordering-1',
envelope: { version: 1, delivery: counter },
user: new mongoose.Types.ObjectId(),
tenantId: 'tenant-1',
availableAt: START,
...overrides,
};
}
function transientFailure(overrides: Partial<AgentTriggerDeliveryFailure> = {}) {
return {
code: 'RATE_LIMITED',
message: 'try later',
certainty: 'definite' as const,
retryable: true,
attemptedAt: START,
status: 429,
...overrides,
};
}
describe('agent trigger delivery methods', () => {
it('enqueues idempotently and rejects key reuse with different content', async () => {
const input = enqueueInput();
const first = await methods.enqueueAgentTriggerDelivery(input);
const replay = await methods.enqueueAgentTriggerDelivery(input);
expect(first.replayed).toBe(false);
expect(first.delivery).toMatchObject({ status: 'pending', attempts: 0 });
expect(replay).toMatchObject({ replayed: true, delivery: { id: first.delivery.id } });
await expect(
methods.enqueueAgentTriggerDelivery({ ...input, fingerprint: 'different' }),
).rejects.toBeInstanceOf(AgentTriggerDeliveryConflictError);
expect(await Delivery.countDocuments()).toBe(1);
});
it('keeps the original mailbox rollout semantics on idempotent replay', async () => {
const enabled = enqueueInput({ awaitTerminalHandling: true });
const first = await methods.enqueueAgentTriggerDelivery(enabled);
const disabledReplay = await methods.enqueueAgentTriggerDelivery({
...enabled,
awaitTerminalHandling: undefined,
});
expect(first.delivery.awaitTerminalHandling).toBe(true);
expect(disabledReplay).toMatchObject({
replayed: true,
delivery: { id: first.delivery.id, awaitTerminalHandling: true },
});
const disabled = enqueueInput();
const second = await methods.enqueueAgentTriggerDelivery(disabled);
const enabledReplay = await methods.enqueueAgentTriggerDelivery({
...disabled,
awaitTerminalHandling: true,
});
expect(second.delivery.awaitTerminalHandling).toBeUndefined();
expect(enabledReplay).toMatchObject({ replayed: true, delivery: { id: second.delivery.id } });
expect(enabledReplay.delivery.awaitTerminalHandling).toBeUndefined();
});
it('projects public status while enforcing API key, owner, and tenant in the query', async () => {
const user = new mongoose.Types.ObjectId();
const queued = await methods.enqueueAgentTriggerDelivery(
enqueueInput({
user,
tenantId: 'tenant-1',
envelope: {
event: { source: { id: 'source-key-1', type: 'remote_api_key' } },
privatePayload: 'x'.repeat(1024),
},
}),
);
const status = await methods.getAgentTriggerDeliveryStatus(
queued.delivery.deliveryKey,
user,
'source-key-1',
'tenant-1',
);
expect(status).toEqual({
deliveryKey: queued.delivery.deliveryKey,
status: 'pending',
attempts: 0,
availableAt: START,
createdAt: expect.any(Date),
});
expect(status).not.toHaveProperty('envelope');
expect(status).not.toHaveProperty('orderingKey');
expect(status).not.toHaveProperty('history');
await expect(
methods.getAgentTriggerDeliveryStatus(
queued.delivery.deliveryKey,
new mongoose.Types.ObjectId(),
'source-key-1',
'tenant-1',
),
).resolves.toBeNull();
const internal = await methods.enqueueAgentTriggerDelivery(
enqueueInput({
user,
tenantId: 'tenant-1',
envelope: { event: { source: { id: 'source-key-1', type: 'schedule' } } },
}),
);
await expect(
methods.getAgentTriggerDeliveryStatus(
internal.delivery.deliveryKey,
user,
'source-key-1',
'tenant-1',
),
).resolves.toBeNull();
await expect(
methods.getAgentTriggerDeliveryStatus(
queued.delivery.deliveryKey,
user,
'source-key-1',
'tenant-2',
),
).resolves.toBeNull();
await expect(
methods.getAgentTriggerDeliveryStatus(
queued.delivery.deliveryKey,
user,
'source-key-2',
'tenant-1',
),
).resolves.toBeNull();
});
it('grants one atomic winner across concurrent claims', async () => {
await methods.enqueueAgentTriggerDelivery(enqueueInput());
const claims = await Promise.all(
Array.from({ length: 8 }, (_, index) =>
methods.claimNextAgentTriggerDelivery({
workerId: `worker-${index}`,
claimToken: `claim-${index}`,
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
}),
),
);
expect(claims.filter((claim) => claim != null)).toHaveLength(1);
});
it('allocates a replica-stable monotonic sequence within an ordering lane', async () => {
const user = new mongoose.Types.ObjectId();
const replicas = [
createAgentTriggerDeliveryMethods(mongoose),
createAgentTriggerDeliveryMethods(mongoose),
];
const enqueued = await Promise.all(
Array.from({ length: 12 }, (_, index) =>
replicas[index % replicas.length].enqueueAgentTriggerDelivery(
enqueueInput({ user, orderingKey: 'shared-lane' }),
),
),
);
expect(enqueued.map(({ delivery }) => delivery.laneSequence).sort((a, b) => a - b)).toEqual(
Array.from({ length: 12 }, (_, index) => index + 1),
);
});
it('coalesces a concurrent replica burst behind one claimable root and settles every receipt', async () => {
const user = new mongoose.Types.ObjectId();
const coalesceUntil = new Date(Date.now() + 60_000);
const coalesceFrom = new Date(coalesceUntil.getTime() - 750);
const replicas = [
createAgentTriggerDeliveryMethods(mongoose),
createAgentTriggerDeliveryMethods(mongoose),
];
const inputs = Array.from({ length: 4 }, (_, index) =>
enqueueInput({
user,
orderingKey: 'commentary-lane',
coalesceKey: 'trigger_batch_commentary',
coalesceFrom,
coalesceUntil,
availableAt: coalesceUntil,
awaitTerminalHandling: true,
envelopeBytes: 128,
envelope: {
mode: 'continue',
target: { bindingId: 'binding-1' },
event: {
id: `event-${index}`,
source: { id: 'source-key', type: 'remote_api_key' },
},
},
}),
);
const queued = await Promise.all(
inputs.map((input, index) =>
replicas[index % replicas.length].enqueueAgentTriggerDelivery(input),
),
);
const persisted = await Delivery.find({ orderingKey: 'commentary-lane' })
.sort({ laneSequence: 1 })
.lean();
const [root] = persisted.filter((row) => row.status === 'pending');
expect(persisted.filter((row) => row.status === 'pending')).toHaveLength(1);
expect(persisted.filter((row) => row.status === 'batched')).toHaveLength(3);
expect(root).toMatchObject({ batchSize: 4, batchBytes: 512 });
expect(root?.batchMemberIds).toHaveLength(3);
const claims = await Promise.all(
replicas.map((replica, index) =>
replica.claimNextAgentTriggerDelivery({
workerId: `worker-${index}`,
claimToken: `claim-${index}`,
now: coalesceUntil,
leaseUntil: new Date(coalesceUntil.getTime() + 60_000),
}),
),
);
const [claim] = claims.filter((candidate) => candidate != null);
expect(claims.filter((candidate) => candidate != null)).toHaveLength(1);
expect(claim).toBeDefined();
const members = await methods.getAgentTriggerDeliveryBatch(claim!);
expect(members.map((member) => member.deliveryKey)).toHaveLength(3);
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claim!.id,
workerId: claim!.leaseBy,
claimToken: claim!.claimToken,
now: coalesceUntil,
});
const result = {
mode: 'continue',
status: 'started',
conversationId: 'child-thread',
streamId: 'child-thread',
generationCreatedAt: 1_787_000_000_000,
};
await expect(
methods.completeAgentTriggerDelivery({
id: claim!.id,
workerId: claim!.leaseBy,
claimToken: claim!.claimToken,
attempt: attempt!,
result,
settledAt: coalesceUntil,
awaitTerminalHandling: true,
handling: {
status: 'started',
conversationId: 'child-thread',
streamId: 'child-thread',
generationCreatedAt: 1_787_000_000_000,
startedAt: coalesceUntil,
},
}),
).resolves.toBe(true);
const settled = await Delivery.find({ orderingKey: 'commentary-lane' }).lean();
expect(settled).toHaveLength(4);
expect(settled.every((row) => row.status === 'succeeded')).toBe(true);
expect(settled.map((row) => row.result)).toEqual(Array(4).fill(result));
expect(new Set(queued.map(({ delivery }) => delivery.deliveryKey)).size).toBe(4);
const receipts = await Promise.all(
queued.map(({ delivery }) =>
methods.getAgentTriggerDeliveryStatus(delivery.deliveryKey, user, 'source-key', 'tenant-1'),
),
);
expect(receipts).toHaveLength(4);
expect(receipts.every((receipt) => receipt?.status === 'succeeded')).toBe(true);
expect(receipts.every((receipt) => receipt?.handling?.status === 'started')).toBe(true);
expect(
(
await Delivery.find({ _id: { $in: queued.map(({ delivery }) => delivery.id) } }).lean()
).every((row) => row.expiresAt == null),
).toBe(true);
const later = await methods.enqueueAgentTriggerDelivery(
enqueueInput({
user,
orderingKey: 'commentary-lane',
awaitTerminalHandling: true,
availableAt: coalesceUntil,
}),
);
const laterClaim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-later',
claimToken: 'claim-later',
now: coalesceUntil,
leaseUntil: new Date(coalesceUntil.getTime() + 60_000),
});
expect(laterClaim?.id).toBe(later.delivery.id);
await expect(methods.findEarlierAgentTriggerDelivery(laterClaim!)).resolves.toMatchObject({
reason: 'active_handling',
});
await expect(
methods.settleAgentTriggerHandlingOutcome({
deliveryKey: root!.deliveryKey,
conversationId: 'child-thread',
generationCreatedAt: 1_787_000_000_000,
status: 'completed_no_action',
settledAt: new Date(coalesceUntil.getTime() + 1_000),
}),
).resolves.toBe(true);
await expect(methods.findEarlierAgentTriggerDelivery(laterClaim!)).resolves.toBeNull();
let terminal = await Delivery.find({ orderingKey: 'commentary-lane' }).lean();
const batchIds = new Set(queued.map(({ delivery }) => delivery.id));
expect(
terminal
.filter((row) => batchIds.has(String(row._id)))
.every((row) => row.handling?.status === 'completed_no_action'),
).toBe(true);
const recoveringMember = terminal.find(
(row) => batchIds.has(String(row._id)) && String(row._id) !== String(root!._id),
);
await Delivery.updateOne(
{ _id: recoveringMember!._id },
{ $set: { 'handling.status': 'started' } },
);
await expect(methods.findEarlierAgentTriggerDelivery(laterClaim!)).resolves.toBeNull();
await Delivery.updateOne({ _id: recoveringMember!._id }, { $unset: { handling: 1 } });
await expect(
methods.settleAgentTriggerHandlingOutcome({
deliveryKey: root!.deliveryKey,
conversationId: 'child-thread',
generationCreatedAt: 1_787_000_000_000,
status: 'completed_no_action',
settledAt: new Date(coalesceUntil.getTime() + 1_000),
}),
).resolves.toBe(true);
terminal = await Delivery.find({ orderingKey: 'commentary-lane' }).lean();
expect(
terminal
.filter((row) => batchIds.has(String(row._id)))
.every((row) => row.handling?.status === 'completed_no_action'),
).toBe(true);
expect(
terminal
.filter((row) => batchIds.has(String(row._id)))
.every(
(row) =>
row.expiresAt?.getTime() === coalesceUntil.getTime() + 1_000 + 90 * 24 * 60 * 60_000,
),
).toBe(true);
});
it('promotes mailbox semantics when an enabled delivery joins an unmarked batch root', async () => {
const user = new mongoose.Types.ObjectId();
const coalesceUntil = new Date(Date.now() + 60_000);
const shared = {
user,
orderingKey: 'mixed-rollout-batch',
coalesceKey: 'trigger_batch_mixed_rollout',
coalesceFrom: new Date(coalesceUntil.getTime() - 750),
coalesceUntil,
availableAt: coalesceUntil,
envelopeBytes: 128,
};
const first = await methods.enqueueAgentTriggerDelivery(enqueueInput(shared));
await methods.enqueueAgentTriggerDelivery(
enqueueInput({ ...shared, awaitTerminalHandling: true }),
);
const root = await Delivery.findById(first.delivery.id).lean();
expect(root).toMatchObject({
status: 'pending',
awaitTerminalHandling: true,
batchSize: 2,
});
});
it('recovers batch receipts and lane cleanup after root settlement was interrupted', async () => {
const user = new mongoose.Types.ObjectId();
const coalesceUntil = new Date(Date.now() + 60_000);
const coalesceFrom = new Date(coalesceUntil.getTime() - 750);
await Promise.all(
Array.from({ length: 2 }, (_, index) =>
methods.enqueueAgentTriggerDelivery(
enqueueInput({
user,
orderingKey: 'batch-recovery-lane',
coalesceKey: 'trigger_batch_recovery',
coalesceFrom,
coalesceUntil,
availableAt: coalesceUntil,
envelopeBytes: 128,
envelope: {
event: {
id: `recovery-event-${index}`,
source: { id: 'source-key', type: 'remote_api_key' },
},
},
}),
),
),
);
const root = await Delivery.findOne({
orderingKey: 'batch-recovery-lane',
status: 'pending',
}).lean();
expect(root?._id).toBeDefined();
const result = { mode: 'continue', status: 'started', conversationId: 'child-thread' };
await Delivery.updateOne(
{ _id: root!._id },
{
$set: {
status: 'succeeded',
attempts: 1,
result,
settledAt: START,
expiresAt: new Date(START.getTime() + 90 * 24 * 60 * 60_000),
laneCleanupPendingAt: START,
},
},
);
await expect(methods.recoverAgentTriggerBatchReceipts()).resolves.toBe(1);
const deliveries = await Delivery.find({ orderingKey: 'batch-recovery-lane' }).lean();
expect(deliveries).toHaveLength(2);
expect(deliveries.every((delivery) => delivery.status === 'succeeded')).toBe(true);
expect(deliveries.map((delivery) => delivery.result)).toEqual(Array(2).fill(result));
expect(deliveries.find((delivery) => String(delivery._id) === String(root!._id))).toMatchObject(
{
batchMembersSettledAt: START,
},
);
expect(await LaneSequence.exists({ _id: 'batch-recovery-lane' })).toBeNull();
await expect(methods.recoverAgentTriggerBatchReceipts()).resolves.toBe(0);
const histories = await Delivery.find({ orderingKey: 'batch-recovery-lane' })
.select('history')
.lean();
expect(histories.map(({ history }) => history?.length ?? 0).sort()).toEqual([0, 1]);
});
it('starts the next linear batch outside the collection window and enforces the size cap', async () => {
const user = new mongoose.Types.ObjectId();
const openUntil = new Date(Date.now() + 60_000);
const openFrom = new Date(openUntil.getTime() - 750);
const inputs = Array.from({ length: 9 }, () =>
enqueueInput({
user,
orderingKey: 'bounded-lane',
coalesceKey: 'trigger_batch_bounded',
coalesceFrom: openFrom,
coalesceUntil: openUntil,
availableAt: openUntil,
envelopeBytes: 64,
}),
);
await Promise.all(inputs.map((input) => methods.enqueueAgentTriggerDelivery(input)));
expect(await Delivery.countDocuments({ orderingKey: 'bounded-lane', status: 'pending' })).toBe(
2,
);
expect(await Delivery.countDocuments({ orderingKey: 'bounded-lane', status: 'batched' })).toBe(
7,
);
const closedUntil = new Date(Date.now() - 1);
const closedFrom = new Date(closedUntil.getTime() - 750);
await methods.enqueueAgentTriggerDelivery(
enqueueInput({
user,
orderingKey: 'closed-lane',
coalesceKey: 'trigger_batch_closed',
coalesceFrom: closedFrom,
coalesceUntil: closedUntil,
availableAt: closedUntil,
envelopeBytes: 64,
}),
);
await methods.enqueueAgentTriggerDelivery(
enqueueInput({
user,
orderingKey: 'closed-lane',
coalesceKey: 'trigger_batch_closed',
coalesceFrom: closedFrom,
coalesceUntil: closedUntil,
availableAt: closedUntil,
envelopeBytes: 64,
}),
);
expect(await Delivery.countDocuments({ orderingKey: 'closed-lane', status: 'pending' })).toBe(
2,
);
const nearUntil = new Date(Date.now() + 60_000);
const distantUntil = new Date(nearUntil.getTime() + 24 * 60 * 60_000);
const nearFrom = new Date(nearUntil.getTime() - 750);
const distantFrom = new Date(distantUntil.getTime() - 750);
await methods.enqueueAgentTriggerDelivery(
enqueueInput({
user,
orderingKey: 'scheduled-lane',
coalesceKey: 'trigger_batch_scheduled',
coalesceFrom: nearFrom,
coalesceUntil: nearUntil,
availableAt: nearUntil,
envelopeBytes: 64,
}),
);
await methods.enqueueAgentTriggerDelivery(
enqueueInput({
user,
orderingKey: 'scheduled-lane',
coalesceKey: 'trigger_batch_scheduled',
coalesceFrom: distantFrom,
coalesceUntil: distantUntil,
availableAt: distantUntil,
envelopeBytes: 64,
}),
);
expect(
await Delivery.countDocuments({ orderingKey: 'scheduled-lane', status: 'pending' }),
).toBe(2);
});
it('intersects overlapping batch windows regardless of publication order', async () => {
const user = new mongoose.Types.ObjectId();
const earlierFrom = new Date(Date.now() + 60_000);
const earlierUntil = new Date(earlierFrom.getTime() + 750);
const laterFrom = new Date(earlierFrom.getTime() + 250);
const laterUntil = new Date(laterFrom.getTime() + 750);
const shared = {
user,
orderingKey: 'overlapping-window-lane',
coalesceKey: 'trigger_batch_overlapping',
envelopeBytes: 64,
};
await methods.enqueueAgentTriggerDelivery(
enqueueInput({
...shared,
coalesceFrom: laterFrom,
coalesceUntil: laterUntil,
availableAt: laterUntil,
}),
);
await methods.enqueueAgentTriggerDelivery(
enqueueInput({
...shared,
coalesceFrom: earlierFrom,
coalesceUntil: earlierUntil,
availableAt: earlierUntil,
}),
);
const rows = await Delivery.find({ orderingKey: shared.orderingKey }).lean();
const root = rows.find((row) => row.status === 'pending');
expect(rows.filter((row) => row.status === 'pending')).toHaveLength(1);
expect(rows.filter((row) => row.status === 'batched')).toHaveLength(1);
expect(root).toMatchObject({
batchSize: 2,
coalesceFrom: laterFrom,
coalesceUntil: earlierUntil,
availableAt: earlierUntil,
});
});
it('starts a new batch when another delivery has taken the lane tail', async () => {
const user = new mongoose.Types.ObjectId();
const coalesceFrom = new Date(Date.now() + 60_000);
const coalesceUntil = new Date(coalesceFrom.getTime() + 750);
const shared = {
user,
orderingKey: 'intervening-delivery-lane',
coalesceFrom,
coalesceUntil,
availableAt: coalesceUntil,
envelopeBytes: 64,
};
await methods.enqueueAgentTriggerDelivery(
enqueueInput({ ...shared, coalesceKey: 'trigger_batch_first' }),
);
await methods.enqueueAgentTriggerDelivery(
enqueueInput({ ...shared, coalesceKey: 'trigger_batch_intervening' }),
);
await methods.enqueueAgentTriggerDelivery(
enqueueInput({ ...shared, coalesceKey: 'trigger_batch_first' }),
);
const rows = await Delivery.find({ orderingKey: shared.orderingKey })
.sort({ laneSequence: 1 })
.lean();
expect(rows.map(({ status }) => status)).toEqual(['pending', 'pending', 'pending']);
expect(rows.map(({ batchSize }) => batchSize)).toEqual([1, 1, 1]);
});
it('requeues a dead batch as a root instead of nesting it under a newer batch', async () => {
const user = new mongoose.Types.ObjectId();
const coalesceUntil = new Date(Date.now() + 60_000);
const coalesceFrom = new Date(coalesceUntil.getTime() - 750);
const shared = {
user,
orderingKey: 'batch-requeue-lane',
coalesceKey: 'trigger_batch_requeue',
coalesceFrom,
coalesceUntil,
availableAt: coalesceUntil,
envelopeBytes: 128,
};
await Promise.all(
Array.from({ length: 2 }, () => methods.enqueueAgentTriggerDelivery(enqueueInput(shared))),
);
const claim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: coalesceUntil,
leaseUntil: new Date(coalesceUntil.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: coalesceUntil,
});
await methods.deadLetterAgentTriggerDelivery({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
error: transientFailure({ retryable: false }),
settledAt: coalesceUntil,
});
await methods.enqueueAgentTriggerDelivery(enqueueInput(shared));
const requeued = await methods.requeueAgentTriggerDelivery(claim!.id, coalesceUntil);
expect(requeued).toMatchObject({ status: 'pending', batchSize: 2 });
expect(requeued?.requeueCount).toBe(1);
expect(requeued?.batchRootId).toBeUndefined();
const rows = await Delivery.find({ orderingKey: 'batch-requeue-lane' }).lean();
expect(rows.filter((row) => row.status === 'pending')).toHaveLength(2);
expect(
rows.filter((row) => row.batchRootId != null && String(row.batchRootId) === claim!.id),
).toHaveLength(1);
expect(rows.find((row) => row.status === 'batched')?.batchRootRequeueCount).toBe(1);
});
it('does not let stale batch operations overwrite a receipt from a newer generation', async () => {
const user = new mongoose.Types.ObjectId();
const coalesceUntil = new Date(Date.now() + 60_000);
const shared = {
user,
orderingKey: 'batch-generation-lane',
coalesceKey: 'trigger_batch_generation',
coalesceFrom: new Date(coalesceUntil.getTime() - 750),
coalesceUntil,
availableAt: coalesceUntil,
envelopeBytes: 128,
};
await Promise.all(
Array.from({ length: 2 }, () => methods.enqueueAgentTriggerDelivery(enqueueInput(shared))),
);
const claim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: coalesceUntil,
leaseUntil: new Date(coalesceUntil.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: coalesceUntil,
});
await methods.deadLetterAgentTriggerDelivery({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
error: transientFailure({ retryable: false }),
settledAt: coalesceUntil,
});
const root = await Delivery.findById(claim!.id).lean();
const memberId = root!.batchMemberIds![0];
await Delivery.updateOne({ _id: root!._id }, { $unset: { batchMembersSettledAt: 1 } });
await Delivery.updateOne(
{ _id: memberId },
{
$set: {
status: 'succeeded',
batchRootRequeueCount: 1,
settledAt: new Date(coalesceUntil.getTime() + 1_000),
},
$unset: { lastError: 1 },
},
);
await expect(methods.requeueAgentTriggerDelivery(claim!.id, coalesceUntil)).rejects.toThrow(
'Not every agent trigger batch receipt could be prepared for requeue',
);
await expect(Delivery.findById(memberId).lean()).resolves.toMatchObject({
status: 'succeeded',
batchRootRequeueCount: 1,
});
await expect(methods.recoverAgentTriggerBatchReceipts()).rejects.toThrow(
'Not every agent trigger batch receipt could be settled',
);
await expect(Delivery.findById(memberId).lean()).resolves.toMatchObject({
status: 'succeeded',
batchRootRequeueCount: 1,
});
expect((await Delivery.findById(root!._id).lean())?.batchMembersSettledAt).toBeUndefined();
});
it('retries safely when batch requeue stops after preparing its members', async () => {
const user = new mongoose.Types.ObjectId();
const coalesceUntil = new Date(Date.now() + 60_000);
const shared = {
user,
orderingKey: 'batch-requeue-recovery-lane',
coalesceKey: 'trigger_batch_requeue_recovery',
coalesceFrom: new Date(coalesceUntil.getTime() - 750),
coalesceUntil,
availableAt: coalesceUntil,
envelopeBytes: 128,
};
await Promise.all(
Array.from({ length: 2 }, () => methods.enqueueAgentTriggerDelivery(enqueueInput(shared))),
);
const claim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: coalesceUntil,
leaseUntil: new Date(coalesceUntil.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: coalesceUntil,
});
await methods.deadLetterAgentTriggerDelivery({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
error: transientFailure({ retryable: false }),
settledAt: coalesceUntil,
});
const transition = jest.spyOn(Delivery, 'findOneAndUpdate').mockImplementationOnce(() => {
throw new Error('process interrupted before root transition');
});
await expect(methods.requeueAgentTriggerDelivery(claim!.id, coalesceUntil)).rejects.toThrow(
'process interrupted before root transition',
);
transition.mockRestore();
await expect(Delivery.findById(claim!.id).lean()).resolves.toMatchObject({
status: 'dead',
requeueCount: 0,
});
const preparedMember = await Delivery.findOne({ batchRootId: claim!.id }).lean();
expect(preparedMember).toMatchObject({ status: 'batched', batchRootRequeueCount: 1 });
await expect(
methods.requeueAgentTriggerDelivery(claim!.id, coalesceUntil),
).resolves.toMatchObject({ status: 'pending', requeueCount: 1 });
await expect(Delivery.findById(preparedMember!._id).lean()).resolves.toMatchObject({
status: 'batched',
batchRootRequeueCount: 1,
});
});
it('publishes an abandoned lane owner before allocating the next sequence', async () => {
const user = new mongoose.Types.ObjectId();
const orderingKey = 'publication-race';
const firstInput = enqueueInput({ user, orderingKey, availableAt: START });
const first = await Delivery.create({
...firstInput,
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
});
await LaneSequence.create({
_id: orderingKey,
value: 1,
user,
tailDeliveryId: first._id,
publisherDeliveryId: first._id,
publisherStartedAt: START,
});
const second = await methods.enqueueAgentTriggerDelivery(
enqueueInput({ user, orderingKey, availableAt: START }),
);
await expect(Delivery.findById(first._id).lean()).resolves.toMatchObject({
status: 'pending',
laneSequence: 1,
});
expect(second.delivery).toMatchObject({ status: 'pending', laneSequence: 2 });
await expect(methods.findEarlierAgentTriggerDelivery(second.delivery)).resolves.toEqual({
availableAt: START,
});
await expect(LaneSequence.findById(orderingKey).lean()).resolves.toMatchObject({ value: 2 });
expect((await LaneSequence.findById(orderingKey).lean())?.publisherDeliveryId).toBeUndefined();
});
it('publishes an orphaned staging row before a later delivery in the lane', async () => {
const user = new mongoose.Types.ObjectId();
const orderingKey = 'orphaned-staging';
const firstInput = enqueueInput({ user, orderingKey, availableAt: START });
const first = await Delivery.create({
...firstInput,
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
});
const second = await methods.enqueueAgentTriggerDelivery(
enqueueInput({ user, orderingKey, availableAt: START }),
);
await expect(Delivery.findById(first._id).lean()).resolves.toMatchObject({
status: 'pending',
laneSequence: 1,
});
expect(second.delivery).toMatchObject({ status: 'pending', laneSequence: 2 });
await expect(methods.findEarlierAgentTriggerDelivery(second.delivery)).resolves.toEqual({
availableAt: START,
});
});
it('discovers an orphaned staging row during maintenance recovery', async () => {
const user = new mongoose.Types.ObjectId();
const orderingKey = 'maintenance-staging';
const staged = await Delivery.create({
...enqueueInput({ user, orderingKey }),
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
stagingRecoveryAt: START,
});
await expect(methods.recoverAgentTriggerLanePublications(1)).resolves.toBe(1);
await expect(Delivery.findById(staged._id).lean()).resolves.toMatchObject({
status: 'pending',
laneSequence: 1,
});
await expect(LaneSequence.findById(orderingKey).lean()).resolves.toMatchObject({ value: 1 });
});
it('backfills and recovers a staging row created before the fairness cursor existed', async () => {
const user = new mongoose.Types.ObjectId();
const orderingKey = 'legacy-maintenance-staging';
const staged = await Delivery.create({
...enqueueInput({ user, orderingKey }),
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
});
await expect(methods.recoverAgentTriggerLanePublications(1)).resolves.toBe(1);
await expect(Delivery.findById(staged._id).lean()).resolves.toMatchObject({
status: 'pending',
laneSequence: 1,
});
});
it('leaves staging unpublished while its durable user purge marker exists', async () => {
const user = new mongoose.Types.ObjectId();
const orderingKey = 'purge-fenced-staging';
await UserPurge.create({ _id: user, fenceStartedAt: START, tenantId: 'tenant-1' });
const staged = await Delivery.create({
...enqueueInput({ user, orderingKey }),
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
stagingRecoveryAt: START,
});
await expect(methods.recoverAgentTriggerLanePublications(1)).resolves.toBe(0);
await expect(Delivery.findById(staged._id).lean()).resolves.toMatchObject({
status: 'staging',
laneSequence: 0,
});
await expect(LaneSequence.findById(orderingKey)).resolves.toBeNull();
});
it('leaves an existing lane publisher fenced while its user purge marker exists', async () => {
const user = new mongoose.Types.ObjectId();
const orderingKey = 'purge-fenced-publisher';
await UserPurge.create({ _id: user, fenceStartedAt: START, tenantId: 'tenant-1' });
const staged = await Delivery.create({
...enqueueInput({ user, orderingKey }),
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
});
await LaneSequence.create({
_id: orderingKey,
value: 1,
user,
tailDeliveryId: staged._id,
publisherDeliveryId: staged._id,
publisherStartedAt: START,
});
await expect(methods.recoverAgentTriggerLanePublications(1)).resolves.toBe(0);
await expect(Delivery.findById(staged._id).lean()).resolves.toMatchObject({
status: 'staging',
laneSequence: 0,
});
await expect(LaneSequence.findById(orderingKey).lean()).resolves.toMatchObject({
publisherDeliveryId: staged._id,
value: 1,
});
});
it('rotates purge-fenced staging rows so later recovery work is not starved', async () => {
const users = Array.from({ length: 3 }, () => new mongoose.Types.ObjectId());
for (let index = 0; index < users.length; index += 1) {
if (index < 2) {
await UserPurge.create({ _id: users[index], fenceStartedAt: START });
}
await Delivery.create({
...enqueueInput({ user: users[index], orderingKey: `staging-rotation-${index}` }),
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
stagingRecoveryAt: new Date(START.getTime() + index),
});
}
await expect(methods.recoverAgentTriggerLanePublications(2)).resolves.toBe(0);
await expect(methods.recoverAgentTriggerLanePublications(2)).resolves.toBe(1);
await expect(
Delivery.findOne({ orderingKey: 'staging-rotation-2' }).lean(),
).resolves.toMatchObject({ status: 'pending', laneSequence: 1 });
});
it('rotates purge-fenced publishers so later recovery work is not starved', async () => {
const users = Array.from({ length: 3 }, () => new mongoose.Types.ObjectId());
for (let index = 0; index < users.length; index += 1) {
if (index < 2) {
await UserPurge.create({ _id: users[index], fenceStartedAt: START });
}
const orderingKey = `publisher-rotation-${index}`;
const staged = await Delivery.create({
...enqueueInput({ user: users[index], orderingKey }),
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
stagingRecoveryAt: START,
});
await LaneSequence.create({
_id: orderingKey,
value: 1,
user: users[index],
publisherDeliveryId: staged._id,
publisherStartedAt: new Date(START.getTime() + index),
});
}
await expect(methods.recoverAgentTriggerLanePublications(2)).resolves.toBe(0);
await expect(methods.recoverAgentTriggerLanePublications(2)).resolves.toBe(1);
await expect(
Delivery.findOne({ orderingKey: 'publisher-rotation-2' }).lean(),
).resolves.toMatchObject({ status: 'pending', laneSequence: 1 });
});
it('abandons a lane acquired concurrently with a new purge marker', async () => {
const user = new mongoose.Types.ObjectId();
const orderingKey = 'purge-race-staging';
const staged = await Delivery.create({
...enqueueInput({ user, orderingKey }),
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
});
const purgeExists = jest
.spyOn(UserPurge, 'exists')
.mockResolvedValueOnce(null)
.mockResolvedValueOnce({ _id: user } as never);
try {
await expect(methods.recoverAgentTriggerLanePublications(1)).resolves.toBe(0);
} finally {
purgeExists.mockRestore();
}
await expect(Delivery.findById(staged._id).lean()).resolves.toMatchObject({
status: 'staging',
laneSequence: 0,
});
await expect(LaneSequence.findById(orderingKey)).resolves.toBeNull();
});
it('builds a sparse index for the periodic publisher recovery scan', async () => {
const [laneIndexes, deliveryIndexes] = await Promise.all([
LaneSequence.collection.indexes(),
Delivery.collection.indexes(),
]);
expect(laneIndexes).toEqual(
expect.arrayContaining([
expect.objectContaining({ key: { publisherStartedAt: 1 }, sparse: true }),
]),
);
expect(deliveryIndexes).toEqual(
expect.arrayContaining([
expect.objectContaining({ key: { stagingRecoveryAt: 1 }, sparse: true }),
expect.objectContaining({ key: { laneCleanupPendingAt: 1 }, sparse: true }),
]),
);
});
it('publishes an idempotent replay on its persisted ordering lane', async () => {
const user = new mongoose.Types.ObjectId();
const input = enqueueInput({ user, orderingKey: 'original-lane' });
await Delivery.create({
...input,
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
});
const replay = await methods.enqueueAgentTriggerDelivery({
...input,
orderingKey: 'changed-lane',
});
expect(replay).toMatchObject({
replayed: true,
delivery: { orderingKey: 'original-lane', laneSequence: 1, status: 'pending' },
});
await expect(LaneSequence.findById('original-lane').lean()).resolves.toMatchObject({
value: 1,
});
await expect(LaneSequence.findById('changed-lane').lean()).resolves.toBeNull();
});
it('resumes its own abandoned publication without allocating a second sequence', async () => {
const user = new mongoose.Types.ObjectId();
const orderingKey = 'publication-replay';
const input = enqueueInput({ user, orderingKey, availableAt: START });
const staged = await Delivery.create({
...input,
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
});
await LaneSequence.create({
_id: orderingKey,
value: 1,
user,
tailDeliveryId: staged._id,
publisherDeliveryId: staged._id,
publisherStartedAt: START,
});
const replay = await methods.enqueueAgentTriggerDelivery(input);
expect(replay).toMatchObject({ replayed: true, delivery: { laneSequence: 1 } });
await expect(LaneSequence.findById(orderingKey).lean()).resolves.toMatchObject({ value: 1 });
});
it('orders a lane by its atomic sequence instead of tied timestamps or process ObjectIds', async () => {
const user = new mongoose.Types.ObjectId();
const common = {
orderingKey: 'tied-lane',
envelope: { version: 1 },
user,
status: 'pending' as const,
attempts: 0,
availableAt: START,
createdAt: START,
updatedAt: START,
};
await Delivery.create([
{
...common,
_id: new mongoose.Types.ObjectId('ffffffffffffffffffffffff'),
deliveryKey: 'first-by-sequence',
fingerprint: 'first',
laneSequence: 1,
},
{
...common,
_id: new mongoose.Types.ObjectId('000000000000000000000001'),
deliveryKey: 'second-by-sequence',
fingerprint: 'second',
laneSequence: 2,
},
]);
await expect(
methods.findEarlierAgentTriggerDelivery({
orderingKey: 'tied-lane',
laneSequence: 2,
}),
).resolves.toEqual({ availableAt: START });
});
it('honors the lease skew margin before takeover', async () => {
await methods.enqueueAgentTriggerDelivery(enqueueInput());
const first = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
expect(first).not.toBeNull();
await expect(
methods.claimNextAgentTriggerDelivery({
workerId: 'worker-2',
claimToken: 'claim-2',
now: new Date(START.getTime() + 70_000),
leaseUntil: new Date(START.getTime() + 130_000),
}),
).resolves.toBeNull();
await expect(
methods.claimNextAgentTriggerDelivery({
workerId: 'worker-2',
claimToken: 'claim-2',
now: new Date(START.getTime() + 91_000),
leaseUntil: new Date(START.getTime() + 151_000),
}),
).resolves.toMatchObject({ claimToken: 'claim-2', leaseBy: 'worker-2' });
});
it('fences every settlement against a stale claimant', async () => {
await methods.enqueueAgentTriggerDelivery(enqueueInput());
const first = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 10_000),
});
expect(first).not.toBeNull();
const second = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-2',
now: new Date(START.getTime() + 41_000),
leaseUntil: new Date(START.getTime() + 101_000),
});
expect(second).not.toBeNull();
await expect(
methods.completeAgentTriggerDelivery({
id: first!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: 1,
result: { conversationId: 'stale' },
settledAt: START,
}),
).resolves.toBe(false);
await expect(
methods.beginAgentTriggerDeliveryAttempt({
id: second!.id,
workerId: 'worker-1',
claimToken: 'claim-2',
now: new Date(START.getTime() + 41_000),
}),
).resolves.toBe(1);
});
it('blocks a due delivery behind an earlier pending item in its ordering lane', async () => {
const first = await methods.enqueueAgentTriggerDelivery(
enqueueInput({ availableAt: new Date(START.getTime() + 60_000) }),
);
await methods.enqueueAgentTriggerDelivery(enqueueInput());
const claimed = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
expect(claimed?.id).not.toBe(first.delivery.id);
await expect(methods.findEarlierAgentTriggerDelivery(claimed!)).resolves.toEqual({
availableAt: new Date(START.getTime() + 60_000),
});
});
it('keeps a binding lane queued until the earlier child turn settles', async () => {
const user = new mongoose.Types.ObjectId();
const first = await methods.enqueueAgentTriggerDelivery(
enqueueInput({ user, orderingKey: 'binding-lane', awaitTerminalHandling: true }),
);
const firstClaim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
const firstAttempt = await methods.beginAgentTriggerDeliveryAttempt({
id: firstClaim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
});
const generationCreatedAt = START.getTime() + 1_000;
await methods.completeAgentTriggerDelivery({
id: firstClaim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: firstAttempt!,
result: {
mode: 'continue',
status: 'started',
conversationId: 'actor-thread',
streamId: 'actor-thread',
generationCreatedAt,
},
settledAt: new Date(generationCreatedAt),
awaitTerminalHandling: true,
handling: {
status: 'started',
conversationId: 'actor-thread',
streamId: 'actor-thread',
generationCreatedAt,
startedAt: new Date(generationCreatedAt),
},
});
const second = await methods.enqueueAgentTriggerDelivery(
enqueueInput({ user, orderingKey: 'binding-lane', awaitTerminalHandling: true }),
);
const secondClaim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-2',
claimToken: 'claim-2',
now: new Date(generationCreatedAt),
leaseUntil: new Date(generationCreatedAt + 60_000),
});
expect(firstClaim?.id).toBe(first.delivery.id);
expect(second.delivery.laneSequence).toBe(first.delivery.laneSequence + 1);
await expect(methods.findEarlierAgentTriggerDelivery(secondClaim!)).resolves.toMatchObject({
availableAt: START,
reason: 'active_handling',
});
await expect(Delivery.findById(first.delivery.id).lean()).resolves.not.toHaveProperty(
'expiresAt',
);
await expect(
methods.settleAgentTriggerHandlingOutcome({
deliveryKey: first.delivery.deliveryKey,
conversationId: 'actor-thread',
generationCreatedAt,
status: 'applied',
settledAt: new Date(generationCreatedAt + 1_000),
action: { toolName: 'submit_action' },
}),
).resolves.toBe(true);
await expect(Delivery.findById(first.delivery.id).lean()).resolves.toMatchObject({
expiresAt: new Date(generationCreatedAt + 1_000 + 90 * 24 * 60 * 60_000),
});
await expect(methods.findEarlierAgentTriggerDelivery(secondClaim!)).resolves.toBeNull();
});
it('reclaims a binding lane only after its admitted child turn settles', async () => {
const queued = await methods.enqueueAgentTriggerDelivery(
enqueueInput({ orderingKey: 'settling-binding-lane', awaitTerminalHandling: true }),
);
const claim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
});
const generationCreatedAt = START.getTime() + 1_000;
await methods.completeAgentTriggerDelivery({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
result: {
mode: 'continue',
status: 'started',
conversationId: 'actor-thread',
streamId: 'actor-thread',
generationCreatedAt,
},
settledAt: new Date(generationCreatedAt),
awaitTerminalHandling: true,
handling: {
status: 'started',
conversationId: 'actor-thread',
streamId: 'actor-thread',
generationCreatedAt,
startedAt: new Date(generationCreatedAt),
},
});
await expect(LaneSequence.findById('settling-binding-lane')).resolves.not.toBeNull();
await expect(
methods.settleAgentTriggerHandlingOutcome({
deliveryKey: queued.delivery.deliveryKey,
conversationId: 'actor-thread',
generationCreatedAt,
status: 'completed_no_action',
settledAt: new Date(generationCreatedAt + 1_000),
}),
).resolves.toBe(true);
await expect(LaneSequence.findById('settling-binding-lane')).resolves.toBeNull();
});
it('records retry and success outcomes and expires only successful rows', async () => {
const queued = await methods.enqueueAgentTriggerDelivery(enqueueInput());
const first = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: first!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
});
await methods.retryAgentTriggerDelivery({
id: first!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
error: transientFailure(),
availableAt: new Date(START.getTime() + 1_000),
});
const second = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-2',
claimToken: 'claim-2',
now: new Date(START.getTime() + 1_000),
leaseUntil: new Date(START.getTime() + 61_000),
});
const secondAttempt = await methods.beginAgentTriggerDeliveryAttempt({
id: second!.id,
workerId: 'worker-2',
claimToken: 'claim-2',
now: new Date(START.getTime() + 1_000),
});
await methods.completeAgentTriggerDelivery({
id: second!.id,
workerId: 'worker-2',
claimToken: 'claim-2',
attempt: secondAttempt!,
result: { conversationId: 'conversation-1' },
settledAt: new Date(START.getTime() + 2_000),
});
const stored = await methods.getAgentTriggerDelivery(queued.delivery.deliveryKey);
expect(stored).toMatchObject({
status: 'succeeded',
attempts: 2,
result: { conversationId: 'conversation-1' },
history: [
{ attempt: 1, outcome: 'retry', workerId: 'worker-1' },
{ attempt: 2, outcome: 'succeeded', workerId: 'worker-2' },
],
});
expect(stored?.expiresAt?.getTime()).toBe(
new Date(START.getTime() + 2_000).getTime() + 90 * 24 * 60 * 60_000,
);
});
it('projects a bound continuation as started after generation admission', async () => {
const user = new mongoose.Types.ObjectId();
const queued = await methods.enqueueAgentTriggerDelivery(
enqueueInput({
user,
envelope: {
mode: 'continue',
target: { bindingId: 'binding-1' },
event: { source: { id: 'source-key-1', type: 'remote_api_key' } },
},
}),
);
const claimed = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claimed!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
});
await methods.completeAgentTriggerDelivery({
id: claimed!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
result: {
mode: 'continue',
status: 'started',
conversationId: 'conversation-1',
streamId: 'conversation-1',
generationCreatedAt: 1_787_000_000_000,
},
settledAt: new Date(START.getTime() + 1_000),
handling: {
status: 'started',
conversationId: 'conversation-1',
streamId: 'conversation-1',
generationCreatedAt: 1_787_000_000_000,
startedAt: new Date(START.getTime() + 1_000),
},
});
await expect(
methods.getAgentTriggerDeliveryStatus(
queued.delivery.deliveryKey,
user,
'source-key-1',
'tenant-1',
),
).resolves.toMatchObject({
status: 'succeeded',
handling: {
status: 'started',
conversationId: 'conversation-1',
streamId: 'conversation-1',
generationCreatedAt: 1_787_000_000_000,
startedAt: new Date(START.getTime() + 1_000),
},
});
});
it('settles only the exact started generation and rejects stale terminal callbacks', async () => {
const queued = await methods.enqueueAgentTriggerDelivery(
enqueueInput({
envelope: {
mode: 'continue',
target: { bindingId: 'binding-1' },
event: { source: { id: 'source-key-1', type: 'remote_api_key' } },
},
}),
);
const claimed = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claimed!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
});
await methods.completeAgentTriggerDelivery({
id: claimed!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
result: {
mode: 'continue',
status: 'started',
conversationId: 'conversation-1',
streamId: 'conversation-1',
generationCreatedAt: 1_787_000_000_000,
},
settledAt: new Date(START.getTime() + 1_000),
handling: {
status: 'started',
conversationId: 'conversation-1',
streamId: 'conversation-1',
generationCreatedAt: 1_787_000_000_000,
startedAt: new Date(START.getTime() + 1_000),
},
});
await expect(
methods.settleAgentTriggerHandlingOutcome({
deliveryKey: queued.delivery.deliveryKey,
conversationId: 'conversation-1',
generationCreatedAt: 1_786_999_999_999,
status: 'failed',
settledAt: new Date(START.getTime() + 2_000),
error: 'stale failure',
}),
).resolves.toBe(false);
await expect(
methods.settleAgentTriggerHandlingOutcome({
deliveryKey: queued.delivery.deliveryKey,
conversationId: 'conversation-1',
generationCreatedAt: 1_787_000_000_000,
status: 'failed',
settledAt: new Date(START.getTime() + 3_000),
error: 'provider rejected the model',
}),
).resolves.toBe(true);
await expect(
methods.settleAgentTriggerHandlingOutcome({
deliveryKey: queued.delivery.deliveryKey,
conversationId: 'conversation-1',
generationCreatedAt: 1_787_000_000_000,
status: 'applied',
settledAt: new Date(START.getTime() + 4_000),
action: { toolName: 'submit_move' },
}),
).resolves.toBe(false);
await expect(
methods.getAgentTriggerDelivery(queued.delivery.deliveryKey),
).resolves.toMatchObject({
handling: {
status: 'failed',
settledAt: new Date(START.getTime() + 3_000),
error: 'provider rejected the model',
},
});
});
it('reclaims an inactive high-cardinality lane after its tail succeeds', async () => {
const orderingKey = 'one-shot-resource-lane';
await methods.enqueueAgentTriggerDelivery(enqueueInput({ orderingKey }));
const claimed = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claimed!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
});
await expect(
methods.completeAgentTriggerDelivery({
id: claimed!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
result: { ok: true },
settledAt: START,
}),
).resolves.toBe(true);
expect(await LaneSequence.countDocuments({ _id: orderingKey })).toBe(0);
});
it('rediscovers lane cleanup when success commits before its cleanup marker', async () => {
const orderingKey = 'crashed-lane-cleanup';
const queued = await methods.enqueueAgentTriggerDelivery(enqueueInput({ orderingKey }));
const claimed = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claimed!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
});
const laneUpdate = jest
.spyOn(LaneSequence, 'updateOne')
.mockRejectedValueOnce(new Error('down'));
try {
await expect(
methods.completeAgentTriggerDelivery({
id: claimed!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
result: { ok: true },
settledAt: START,
}),
).resolves.toBe(true);
} finally {
laneUpdate.mockRestore();
}
await expect(Delivery.findById(queued.delivery.id).lean()).resolves.toMatchObject({
status: 'succeeded',
laneCleanupPendingAt: START,
});
await expect(methods.reclaimInactiveAgentTriggerLanes(1)).resolves.toBe(1);
await expect(LaneSequence.findById(orderingKey)).resolves.toBeNull();
expect(
(await Delivery.findById(queued.delivery.id).lean())?.laneCleanupPendingAt,
).toBeUndefined();
});
it('restores the retry budget when dispatch is deferred before execution', async () => {
const queued = await methods.enqueueAgentTriggerDelivery(enqueueInput());
const claim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
});
await expect(
methods.deferAgentTriggerDeliveryAttempt({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
availableAt: new Date(START.getTime() + 5_000),
}),
).resolves.toBe(true);
await expect(
methods.getAgentTriggerDelivery(queued.delivery.deliveryKey),
).resolves.toMatchObject({
status: 'pending',
attempts: 0,
availableAt: new Date(START.getTime() + 5_000),
});
});
it('retains dead letters, truncates failure text, and supports explicit requeue', async () => {
const user = new mongoose.Types.ObjectId();
const orderingKey = 'dead-letter-requeue';
const queued = await methods.enqueueAgentTriggerDelivery(enqueueInput({ user, orderingKey }));
const claim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
const attempt = await methods.beginAgentTriggerDeliveryAttempt({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
});
await methods.deadLetterAgentTriggerDelivery({
id: claim!.id,
workerId: 'worker-1',
claimToken: 'claim-1',
attempt: attempt!,
error: transientFailure({
code: 'X'.repeat(256),
message: 'x'.repeat(3_000),
retryable: false,
}),
settledAt: START,
});
const [dead] = await methods.getAgentTriggerDeadLetters();
expect(dead).toMatchObject({ id: queued.delivery.id, status: 'dead' });
expect(dead.lastError?.code).toHaveLength(128);
expect(dead.lastError?.message).toHaveLength(2048);
expect(dead.expiresAt).toBeUndefined();
const later = await methods.enqueueAgentTriggerDelivery(enqueueInput({ user, orderingKey }));
const laterClaim = await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-2',
claimToken: 'claim-2',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
expect(laterClaim?.id).toBe(later.delivery.id);
const stagedAhead = await Delivery.create({
...enqueueInput({ user, orderingKey }),
laneSequence: 0,
status: 'staging',
attempts: 0,
requeueCount: 0,
});
await Delivery.collection.updateOne(
{ _id: stagedAhead._id },
{ $set: { updatedAt: new Date(0) } },
);
const requeued = await methods.requeueAgentTriggerDelivery(dead.id, START);
expect(requeued).toMatchObject({
status: 'pending',
attempts: 0,
requeueCount: 1,
laneSequence: 4,
});
await expect(Delivery.findById(stagedAhead._id).lean()).resolves.toMatchObject({
status: 'pending',
laneSequence: 3,
});
expect(requeued?.lastError).toBeUndefined();
await expect(methods.findEarlierAgentTriggerDelivery(requeued!)).resolves.toEqual({
availableAt: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
expect(await methods.getAgentTriggerDeadLetters()).toEqual([]);
await expect(methods.getAgentTriggerDeadLetters(Number.NaN)).rejects.toThrow(
'Agent trigger dead-letter limit must be a positive integer',
);
});
it('counts only live leases while an account deletion drains', async () => {
const user = new mongoose.Types.ObjectId();
await methods.enqueueAgentTriggerDelivery(enqueueInput({ user }));
await methods.enqueueAgentTriggerDelivery(enqueueInput({ user }));
await methods.claimNextAgentTriggerDelivery({
workerId: 'worker-1',
claimToken: 'claim-1',
now: START,
leaseUntil: new Date(START.getTime() + 60_000),
});
expect(await methods.countActiveAgentTriggerDeliveriesByUser(user, START)).toBe(1);
expect(
await methods.countActiveAgentTriggerDeliveriesByUser(
user,
new Date(START.getTime() + 60_001),
),
).toBe(0);
});
it('deletes all queued payloads for an erased user', async () => {
const user = new mongoose.Types.ObjectId();
const fenceStartedAt = new Date(START);
await User.create({
_id: user,
email: 'immediate-purge@example.com',
provider: 'local',
agentTriggerDeletionStartedAt: fenceStartedAt,
});
await methods.enqueueAgentTriggerDelivery(enqueueInput({ user }));
await methods.enqueueAgentTriggerDelivery(enqueueInput({ user }));
await methods.enqueueAgentTriggerDelivery(enqueueInput({ orderingKey: 'ordering-other' }));
await methods.prepareAgentTriggerUserPurge(user, fenceStartedAt);
await User.deleteOne({ _id: user });
await methods.deleteAgentTriggerDeliveriesByUser(user);
expect(await Delivery.countDocuments({ user })).toBe(0);
expect(await Delivery.countDocuments()).toBe(1);
expect(await LaneSequence.countDocuments({ user })).toBe(0);
expect(await LaneSequence.countDocuments()).toBe(1);
expect(await UserPurge.countDocuments({ _id: user })).toBe(0);
});
it('recovers an armed purge after the user deletion commits', async () => {
const user = new mongoose.Types.ObjectId();
const fenceStartedAt = new Date(START);
await User.create({
_id: user,
email: 'purge@example.com',
provider: 'local',
agentTriggerDeletionStartedAt: fenceStartedAt,
});
await methods.enqueueAgentTriggerDelivery(enqueueInput({ user }));
await methods.prepareAgentTriggerUserPurge(user, fenceStartedAt, 'tenant-1');
await expect(methods.recoverAgentTriggerUserPurges()).resolves.toBe(0);
expect(await Delivery.countDocuments({ user })).toBe(1);
expect(await UserPurge.countDocuments({ _id: user })).toBe(1);
await User.deleteOne({ _id: user });
await expect(methods.recoverAgentTriggerUserPurges()).resolves.toBe(1);
expect(await Delivery.countDocuments({ user })).toBe(0);
expect(await LaneSequence.countDocuments({ user })).toBe(0);
expect(await UserPurge.countDocuments({ _id: user })).toBe(0);
});
it('rotates active purge markers so a later committed purge is recovered', async () => {
const users = Array.from({ length: 3 }, () => new mongoose.Types.ObjectId());
for (const [index, user] of users.entries()) {
await User.create({
_id: user,
email: `purge-rotation-${index}@example.com`,
provider: 'local',
agentTriggerDeletionStartedAt: START,
});
await methods.prepareAgentTriggerUserPurge(user, START);
}
await Delivery.create({
...enqueueInput({ user: users[2], orderingKey: 'committed-purge-lane' }),
laneSequence: 1,
status: 'pending',
attempts: 0,
requeueCount: 0,
});
await User.deleteOne({ _id: users[2] });
await expect(methods.recoverAgentTriggerUserPurges(2)).resolves.toBe(0);
await expect(methods.recoverAgentTriggerUserPurges(2)).resolves.toBe(1);
expect(await UserPurge.countDocuments({ _id: users[2] })).toBe(0);
expect(await Delivery.countDocuments({ user: users[2] })).toBe(0);
expect(await UserPurge.countDocuments({ _id: { $in: users.slice(0, 2) } })).toBe(2);
});
it('disarms a stale purge marker without touching an active user delivery', async () => {
const user = new mongoose.Types.ObjectId();
const fenceStartedAt = new Date(START);
await User.create({
_id: user,
email: 'rollback@example.com',
provider: 'local',
agentTriggerDeletionStartedAt: fenceStartedAt,
});
await methods.enqueueAgentTriggerDelivery(enqueueInput({ user }));
await methods.prepareAgentTriggerUserPurge(user, fenceStartedAt);
await User.updateOne({ _id: user }, { $unset: { agentTriggerDeletionStartedAt: 1 } });
await expect(methods.recoverAgentTriggerUserPurges()).resolves.toBe(0);
expect(await Delivery.countDocuments({ user })).toBe(1);
expect(await UserPurge.countDocuments({ _id: user })).toBe(0);
});
it('lets only the exact deletion owner cancel a prepared purge', async () => {
const user = new mongoose.Types.ObjectId();
const fenceStartedAt = new Date(START);
await User.create({
_id: user,
email: 'owner@example.com',
provider: 'local',
agentTriggerDeletionStartedAt: fenceStartedAt,
});
await methods.prepareAgentTriggerUserPurge(user, fenceStartedAt);
await expect(
methods.cancelAgentTriggerUserPurge(user, new Date(START.getTime() + 1)),
).resolves.toBe(false);
await expect(methods.cancelAgentTriggerUserPurge(user, fenceStartedAt)).resolves.toBe(true);
});
it('cannot disarm purge recovery after the user commit', async () => {
const user = new mongoose.Types.ObjectId();
const fenceStartedAt = new Date(START);
await User.create({
_id: user,
email: 'committed@example.com',
provider: 'local',
agentTriggerDeletionStartedAt: fenceStartedAt,
});
await methods.prepareAgentTriggerUserPurge(user, fenceStartedAt);
await User.deleteOne({ _id: user });
await expect(methods.cancelAgentTriggerUserPurge(user, fenceStartedAt)).resolves.toBe(false);
expect(await UserPurge.countDocuments({ _id: user })).toBe(1);
});
});