agentic-workflow-manager 9.12.4 → 9.12.5
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.
- package/dist/src/commands/watch/apply.js +10 -3
- package/dist/tests/commands/watch/reopened-196.test.js +42 -3
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/secure_fs.node +0 -0
- package/prebuilds/darwin-x64/secure_fs.node +0 -0
- package/prebuilds/win32-arm64/secure_fs.node +0 -0
- package/prebuilds/win32-x64/secure_fs.node +0 -0
|
@@ -542,11 +542,18 @@ function applyRequestToState(s, env, digest, repoRoot, eventScope) {
|
|
|
542
542
|
{ taskId, entity: 'dispatch', dispatchId: existing.id },
|
|
543
543
|
{ taskId, dispatchId: existing.id, entity: 'dispatch' },
|
|
544
544
|
].map(payload => (0, requests_1.digestOf)(payload));
|
|
545
|
-
const
|
|
545
|
+
const appliedAcks = Object.values(s.appliedRequests);
|
|
546
|
+
const oldAckIndex = appliedAcks.findIndex(ack => ack.outcome === 'applied'
|
|
546
547
|
&& ack.resultRef === existing.id && legacyDigests.includes(ack.payloadDigest));
|
|
548
|
+
const reservationAckIndex = appliedAcks.findIndex(ack => ack.requestId === attempt.reservationRequestId);
|
|
549
|
+
// The single writer appends ACKs to appliedRequests and persists
|
|
550
|
+
// their insertion order. Equal millisecond timestamps need this
|
|
551
|
+
// additional durable ordering evidence, not an inferred child.
|
|
552
|
+
const legacyPrecedesReservation = oldAt < reservedAt
|
|
553
|
+
|| (oldAt === reservedAt && oldAckIndex >= 0 && reservationAckIndex > oldAckIndex);
|
|
547
554
|
const safeLegacy = reservedForNewDispatch && Number.isFinite(oldAt) && Number.isFinite(reservedAt)
|
|
548
|
-
&&
|
|
549
|
-
&&
|
|
555
|
+
&& legacyPrecedesReservation
|
|
556
|
+
&& oldAckIndex >= 0
|
|
550
557
|
&& s.dispatches.filter(d => d.taskId === taskId).length === 1
|
|
551
558
|
&& s.tasks.find(t => t.id === taskId)?.attempts === 1
|
|
552
559
|
&& s.tasks.find(t => t.id === taskId)?.status === 'in-progress'
|
|
@@ -224,6 +224,37 @@ describe('issue #196 reopened: supervised S1 handoff', () => {
|
|
|
224
224
|
.toThrow(/conflictivo/);
|
|
225
225
|
expect(state.dispatches).toHaveLength(2);
|
|
226
226
|
});
|
|
227
|
+
test('equal-millisecond legacy timestamps reconcile only when the durable dispatch ACK precedes the reservation ACK', () => {
|
|
228
|
+
const state = v2State();
|
|
229
|
+
const at = state.routingAttempts[0].reservedAt;
|
|
230
|
+
state.dispatches.push({ id: 'dispatch-S1', taskId: 'S1', at });
|
|
231
|
+
state.tasks[0].attempts = 1;
|
|
232
|
+
state.tasks[0].status = 'in-progress';
|
|
233
|
+
const reservationAck = state.appliedRequests['reserve-1'];
|
|
234
|
+
const historicalAck = { requestId: 'old-dispatch-request', idempotencyKey: 'old-dispatch-key',
|
|
235
|
+
payloadDigest: legacyDispatchDigest(), outcome: 'applied', resultRef: 'dispatch-S1' };
|
|
236
|
+
state.appliedRequests = { 'old-dispatch-request': historicalAck, 'reserve-1': reservationAck };
|
|
237
|
+
const durable = JSON.parse(JSON.stringify(state));
|
|
238
|
+
expect(Object.keys(durable.appliedRequests)).toEqual(['old-dispatch-request', 'reserve-1']);
|
|
239
|
+
dispatch(durable, { routingAttemptId: 'route-1' });
|
|
240
|
+
expect(durable.dispatches).toHaveLength(2);
|
|
241
|
+
expect(durable.dispatches[0]).toEqual({ id: 'dispatch-S1', taskId: 'S1', at });
|
|
242
|
+
expect(durable.appliedRequests['old-dispatch-request']).toEqual(historicalAck);
|
|
243
|
+
expect(durable.tasks[0].attempts).toBe(1);
|
|
244
|
+
expect((0, types_1.isWellFormedState)(durable)).toBe(true);
|
|
245
|
+
});
|
|
246
|
+
test('equal-millisecond legacy timestamps do not infer order from a later dispatch ACK', () => {
|
|
247
|
+
const state = v2State();
|
|
248
|
+
state.dispatches.push({ id: 'dispatch-S1', taskId: 'S1', at: state.routingAttempts[0].reservedAt });
|
|
249
|
+
state.tasks[0].attempts = 1;
|
|
250
|
+
state.tasks[0].status = 'in-progress';
|
|
251
|
+
state.appliedRequests['old-dispatch-request'] = { requestId: 'old-dispatch-request',
|
|
252
|
+
idempotencyKey: 'old-dispatch-key', payloadDigest: legacyDispatchDigest(),
|
|
253
|
+
outcome: 'applied', resultRef: 'dispatch-S1' };
|
|
254
|
+
expect(() => dispatch(state, { routingAttemptId: 'route-1' })).toThrow(/legacy handoff/);
|
|
255
|
+
expect(state.dispatches).toHaveLength(1);
|
|
256
|
+
expect(state.appliedRequests['dispatch-request']).toBeUndefined();
|
|
257
|
+
});
|
|
227
258
|
test('historical ACK matching is independent of JSON key order but not payload identity', () => {
|
|
228
259
|
for (const rawJson of [
|
|
229
260
|
'{"taskId":"S1","dispatchId":"dispatch-S1"}',
|
|
@@ -972,10 +1003,10 @@ describe('issue #196 reopened: supervised S1 handoff', () => {
|
|
|
972
1003
|
(0, apply_1.consumePendingRequests)(repo, 'main', generation.token, scope);
|
|
973
1004
|
expect((0, store_1.readJournal)(repo, 'main').state.requestProblems).toEqual([]);
|
|
974
1005
|
expect(cli('ack', task.requestId).state).toBe('applied');
|
|
975
|
-
// Durable 9.12.2 intent
|
|
976
|
-
//
|
|
1006
|
+
// Durable 9.12.2 intent and ACK precede the route reservation.
|
|
1007
|
+
// Equal timestamp granularity alone must not imply a child.
|
|
977
1008
|
const historical = (0, store_1.readJournal)(repo, 'main').state;
|
|
978
|
-
|
|
1009
|
+
let historicalAt = new Date(Date.now() - 60_000).toISOString();
|
|
979
1010
|
historical.dispatches.push({ id: 'dispatch-S1', taskId: 'S1', at: historicalAt });
|
|
980
1011
|
historical.tasks[0].attempts = 1;
|
|
981
1012
|
historical.tasks[0].status = 'in-progress';
|
|
@@ -989,6 +1020,14 @@ describe('issue #196 reopened: supervised S1 handoff', () => {
|
|
|
989
1020
|
const reservation = cli('ack', reserve.requestId);
|
|
990
1021
|
expect(reservation.state).toBe('applied');
|
|
991
1022
|
const attemptId = reservation.resultRef;
|
|
1023
|
+
// Reproduce the real journal's millisecond tie without changing
|
|
1024
|
+
// the durable ACK order or adding any native evidence.
|
|
1025
|
+
const tied = (0, store_1.readJournal)(repo, 'main').state;
|
|
1026
|
+
historicalAt = tied.routingAttempts.find(attempt => attempt.id === attemptId).reservedAt;
|
|
1027
|
+
tied.dispatches[0].at = historicalAt;
|
|
1028
|
+
expect(Object.keys(tied.appliedRequests).indexOf('old-dispatch-request'))
|
|
1029
|
+
.toBeLessThan(Object.keys(tied.appliedRequests).indexOf(reserve.requestId));
|
|
1030
|
+
(0, store_1.writeJournal)(repo, 'main', tied);
|
|
992
1031
|
const dispatchPayload = JSON.stringify({ dispatchId: 'dispatch-S1', taskId: 'S1', routingAttemptId: attemptId });
|
|
993
1032
|
const queuedDispatch = cli('register', '--generation', generation.token, '--entity', 'dispatch', '--json', dispatchPayload);
|
|
994
1033
|
expect(cli('ack', queuedDispatch.requestId).state).toBe('pending');
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|