@@ -270,59 +270,64 @@ describe("CronService restart catch-up", () => {
270270 }
271271 } ) ;
272272
273- it ( "does not defer an isolated cron agent-turn whose persisted due slot already succeeded" , async ( ) => {
274- const store = await makeStorePath ( ) ;
275- const startNow = Date . parse ( "2025-12-13T11:00:00.000Z" ) ;
276- const dueAt = Date . parse ( "2025-12-13T09:10:00.000Z" ) ;
277- const completedAt = Date . parse ( "2025-12-13T09:10:30.000Z" ) ;
278- const runIsolatedAgentJob = vi . fn ( async ( ) => ( { status : "ok" as const } ) ) ;
279- const enqueueSystemEvent = vi . fn ( ) ;
280- const requestHeartbeat = vi . fn ( ) ;
281-
282- await writeStoreJobs ( store . storePath , [
283- {
284- id : "startup-isolated-agent-already-ok" ,
285- name : "startup isolated agent already ok" ,
286- enabled : true ,
287- createdAtMs : Date . parse ( "2025-12-10T12:00:00.000Z" ) ,
288- updatedAtMs : completedAt ,
289- schedule : { kind : "cron" , expr : "10 9 * * *" , tz : "UTC" } ,
290- sessionTarget : "isolated" ,
291- wakeMode : "next-heartbeat" ,
292- payload : { kind : "agentTurn" , message : "daily reminder" } ,
293- state : {
294- nextRunAtMs : dueAt ,
295- lastRunAtMs : completedAt ,
296- lastRunStatus : "ok" ,
273+ it . each ( [ "ok" , "skipped" ] as const ) (
274+ "does not defer an isolated cron agent-turn whose persisted due slot finished as %s" ,
275+ async ( lastRunStatus ) => {
276+ const store = await makeStorePath ( ) ;
277+ const startNow = Date . parse ( "2025-12-13T11:00:00.000Z" ) ;
278+ const dueAt = Date . parse ( "2025-12-13T09:10:00.000Z" ) ;
279+ const completedAt = Date . parse ( "2025-12-13T09:10:30.000Z" ) ;
280+ const runIsolatedAgentJob = vi . fn ( async ( ) => ( { status : "ok" as const } ) ) ;
281+ const enqueueSystemEvent = vi . fn ( ) ;
282+ const requestHeartbeat = vi . fn ( ) ;
283+
284+ await writeStoreJobs ( store . storePath , [
285+ {
286+ id : `startup-isolated-agent-already-${ lastRunStatus } ` ,
287+ name : `startup isolated agent already ${ lastRunStatus } ` ,
288+ enabled : true ,
289+ createdAtMs : Date . parse ( "2025-12-10T12:00:00.000Z" ) ,
290+ updatedAtMs : completedAt ,
291+ schedule : { kind : "cron" , expr : "10 9 * * *" , tz : "UTC" } ,
292+ sessionTarget : "isolated" ,
293+ wakeMode : "next-heartbeat" ,
294+ payload : { kind : "agentTurn" , message : "daily reminder" } ,
295+ state : {
296+ nextRunAtMs : dueAt ,
297+ lastRunAtMs : completedAt ,
298+ lastRunStatus,
299+ } ,
297300 } ,
298- } ,
299- ] ) ;
301+ ] ) ;
300302
301- const cron = createRestartCronService ( {
302- storePath : store . storePath ,
303- enqueueSystemEvent,
304- requestHeartbeat,
305- runIsolatedAgentJob,
306- nowMs : ( ) => startNow ,
307- startupDeferredMissedAgentJobDelayMs : 120_000 ,
308- } ) ;
303+ const cron = createRestartCronService ( {
304+ storePath : store . storePath ,
305+ enqueueSystemEvent,
306+ requestHeartbeat,
307+ runIsolatedAgentJob,
308+ nowMs : ( ) => startNow ,
309+ startupDeferredMissedAgentJobDelayMs : 120_000 ,
310+ } ) ;
309311
310- try {
311- await cron . start ( ) ;
312+ try {
313+ await cron . start ( ) ;
312314
313- expect ( runIsolatedAgentJob ) . not . toHaveBeenCalled ( ) ;
314- expect ( enqueueSystemEvent ) . not . toHaveBeenCalled ( ) ;
315- expect ( requestHeartbeat ) . not . toHaveBeenCalled ( ) ;
315+ expect ( runIsolatedAgentJob ) . not . toHaveBeenCalled ( ) ;
316+ expect ( enqueueSystemEvent ) . not . toHaveBeenCalled ( ) ;
317+ expect ( requestHeartbeat ) . not . toHaveBeenCalled ( ) ;
316318
317- const listedJobs = await cron . list ( { includeDisabled : true } ) ;
318- const updated = listedJobs . find ( ( job ) => job . id === "startup-isolated-agent-already-ok" ) ;
319- expect ( updated ?. state . lastRunStatus ) . toBe ( "ok" ) ;
320- expect ( updated ?. state . nextRunAtMs ) . toBe ( Date . parse ( "2025-12-14T09:10:00.000Z" ) ) ;
321- } finally {
322- cron . stop ( ) ;
323- await store . cleanup ( ) ;
324- }
325- } ) ;
319+ const listedJobs = await cron . list ( { includeDisabled : true } ) ;
320+ const updated = listedJobs . find (
321+ ( job ) => job . id === `startup-isolated-agent-already-${ lastRunStatus } ` ,
322+ ) ;
323+ expect ( updated ?. state . lastRunStatus ) . toBe ( lastRunStatus ) ;
324+ expect ( updated ?. state . nextRunAtMs ) . toBe ( Date . parse ( "2025-12-14T09:10:00.000Z" ) ) ;
325+ } finally {
326+ cron . stop ( ) ;
327+ await store . cleanup ( ) ;
328+ }
329+ } ,
330+ ) ;
326331
327332 it ( "replays a newer missed cron slot behind a completed persisted slot" , async ( ) => {
328333 vi . setSystemTime ( new Date ( "2025-12-13T04:10:00.000Z" ) ) ;
0 commit comments