@@ -607,6 +607,50 @@ it.effect.each(["run.interrupt", "thread.stop"] as const)(
607607 } ) . pipe ( Effect . provide ( layerTest ) ) ,
608608) ;
609609
610+ it . effect ( "a repeated Stop that changes nothing still stops the delegated tasks" , ( ) =>
611+ Effect . gen ( function * ( ) {
612+ const orchestrator = yield * Orchestrator . OrchestratorV2 ;
613+ const projections = yield * ProjectionStore . ProjectionStoreV2 ;
614+ const sql = yield * SqlClient . SqlClient ;
615+ const parentThreadId = ThreadId . make ( "thread:stop-again" ) ;
616+ yield * createWatchingThread ( parentThreadId , 1 ) ;
617+ yield * send ( parentThreadId , "first" , "start_immediately" ) ;
618+ yield * delegate ( parentThreadId , "stop-again child" ) ;
619+ const now = yield * DateTime . now ;
620+ const run = ( yield * orchestrator . getThreadProjection ( parentThreadId ) ) . runs [ 0 ] ! ;
621+ yield * projections . apply ( {
622+ id : EventId . make ( "event:stop-again:run-completed" ) ,
623+ type : "run.updated" ,
624+ threadId : parentThreadId ,
625+ runId : run . id ,
626+ occurredAt : now ,
627+ payload : { ...run , status : "completed" , completedAt : now } ,
628+ } ) ;
629+ yield * orchestrator . dispatch ( {
630+ type : "thread.stop" ,
631+ commandId : CommandId . make ( "stop-again:first" ) ,
632+ threadId : parentThreadId ,
633+ } ) ;
634+
635+ // The first Stop already disposed the delivery and ended the watch, so this one writes no
636+ // events, like Stop on a thread an older server stopped without stopping its children.
637+ const again = yield * orchestrator . dispatch ( {
638+ type : "thread.stop" ,
639+ commandId : CommandId . make ( "stop-again:second" ) ,
640+ threadId : parentThreadId ,
641+ } ) ;
642+ assert . lengthOf ( again . storedEvents , 0 ) ;
643+ const walks = yield * sql < { readonly command_id : string } > `
644+ SELECT command_id FROM orchestration_v2_effect_outbox
645+ WHERE effect_type = 'delegated-tasks.stop'
646+ ` ;
647+ assert . deepEqual (
648+ walks . map ( ( row ) => row . command_id ) ,
649+ [ "stop-again:first" , "stop-again:second" ] ,
650+ ) ;
651+ } ) . pipe ( Effect . provide ( layerTest ) ) ,
652+ ) ;
653+
610654it . effect . each ( [ "thread.stop" , "run.interrupt" ] as const ) (
611655 "%s cancels buffered wakes and preserves durable queued messages" ,
612656 ( type ) =>
0 commit comments