@@ -519,6 +519,57 @@ describe("ClineProvider.delegateParentAndOpenChild()", () => {
519519 expect ( childRun ) . toHaveBeenCalledTimes ( 1 )
520520 } )
521521
522+ it ( "does not abort delegation when the fallback say rejects after the parent is disposed (DTE series 5/5)" , async ( ) => {
523+ const parentTask = makeParentTask ( )
524+ const setRuntimeThinkingEffort = vi . fn ( )
525+ // The parent is already disposed when this say runs, so the webview state can be
526+ // gone and the say rejects (e.g. posting to a removed task).
527+ const say = vi . fn ( ) . mockRejectedValue ( new Error ( "task disposed" ) )
528+ const childRun = vi . fn ( ) . mockResolvedValue ( undefined )
529+ const createTask = vi . fn ( ) . mockResolvedValue ( {
530+ taskId : "child-1" ,
531+ start : vi . fn ( ) ,
532+ run : childRun ,
533+ setRuntimeThinkingEffort,
534+ say,
535+ api : { getModel : ( ) => ( { id : "child-model" , info : { supportsReasoningEffort : [ "low" , "high" ] } } ) } ,
536+ } )
537+ const taskHistoryStore = makeStoreStub ( )
538+ const providerLog = vi . fn ( )
539+
540+ const provider = {
541+ taskScheduler : new TaskScheduler ( ) ,
542+ emit : vi . fn ( ) ,
543+ getCurrentTask : vi . fn ( ( ) => parentTask ) ,
544+ removeClineFromStack : vi . fn ( ) . mockResolvedValue ( undefined ) ,
545+ createTask,
546+ handleModeSwitch : vi . fn ( ) . mockResolvedValue ( undefined ) ,
547+ log : providerLog ,
548+ isViewLaunched : false ,
549+ recentTasksCache : undefined ,
550+ taskHistoryStore,
551+ } as unknown as ClineProvider
552+
553+ // Must NOT reject: the failing notification is non-fatal.
554+ await ClineProvider . prototype . delegateParentAndOpenChild . call ( provider , {
555+ parentTaskId : "parent-1" ,
556+ message : "Do something" ,
557+ initialTodos : [ ] ,
558+ mode : "code" ,
559+ thinkingEffort : "xhigh" ,
560+ } )
561+ await Promise . resolve ( )
562+
563+ // The say rejection is surfaced through the provider log, not thrown.
564+ expect ( providerLog ) . toHaveBeenCalledWith ( expect . stringContaining ( "non-fatal" ) )
565+ expect ( providerLog ) . toHaveBeenCalledWith ( expect . stringContaining ( "task disposed" ) )
566+ // Delegation metadata is still persisted for the (already disposed) parent.
567+ expect ( taskHistoryStore . atomicReadAndUpdate ) . toHaveBeenCalledTimes ( 1 )
568+ expect ( taskHistoryStore . atomicReadAndUpdate . mock . calls [ 0 ] [ 0 ] ) . toBe ( "parent-1" )
569+ // And the child is still scheduled despite the failed notification.
570+ expect ( childRun ) . toHaveBeenCalledTimes ( 1 )
571+ } )
572+
522573 it ( "applies the effort when the child model (post mode switch) has a boolean-true capability (DTE series 5/5)" , async ( ) => {
523574 const parentTask = makeParentTask ( )
524575 const setRuntimeThinkingEffort = vi . fn ( )
0 commit comments