@@ -407,6 +407,241 @@ describe('TraceReducer', () => {
407407 expect ( pipeline . children . map ( ( item ) => item . kind ) ) . toEqual ( [ 'resource_loading' ] )
408408 } )
409409
410+ it ( 'parents outer-task wait_freezes under the active foreign pipeline scope from the same source' , ( ) => {
411+ const events : ProtocolEvent [ ] = [
412+ makeEvent ( {
413+ kind : 'task' ,
414+ seq : 1 ,
415+ ts : '2026-04-08 00:00:01.000' ,
416+ tsMs : 1 ,
417+ processId : 'Px1' ,
418+ threadId : 'Tx1' ,
419+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 1 } ,
420+ rawMessage : 'Tasker.Task.Starting' ,
421+ phase : 'starting' ,
422+ rawDetails : { task_id : 1 , entry : 'Main' } ,
423+ taskId : 1 ,
424+ entry : 'Main' ,
425+ } ) ,
426+ makeEvent ( {
427+ kind : 'pipeline_node' ,
428+ seq : 2 ,
429+ ts : '2026-04-08 00:00:02.000' ,
430+ tsMs : 2 ,
431+ processId : 'Px1' ,
432+ threadId : 'Tx1' ,
433+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 2 } ,
434+ rawMessage : 'Node.PipelineNode.Starting' ,
435+ phase : 'starting' ,
436+ rawDetails : { task_id : 1 , node_id : 101 , name : 'MainNode' } ,
437+ taskId : 1 ,
438+ nodeId : 101 ,
439+ name : 'MainNode' ,
440+ } ) ,
441+ makeEvent ( {
442+ kind : 'action' ,
443+ seq : 3 ,
444+ ts : '2026-04-08 00:00:03.000' ,
445+ tsMs : 3 ,
446+ processId : 'Px1' ,
447+ threadId : 'Tx1' ,
448+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 3 } ,
449+ rawMessage : 'Node.Action.Starting' ,
450+ phase : 'starting' ,
451+ rawDetails : { task_id : 1 , action_id : 601 , name : 'OuterAction' } ,
452+ taskId : 1 ,
453+ actionId : 601 ,
454+ name : 'OuterAction' ,
455+ } ) ,
456+ makeEvent ( {
457+ kind : 'pipeline_node' ,
458+ seq : 4 ,
459+ ts : '2026-04-08 00:00:04.000' ,
460+ tsMs : 4 ,
461+ processId : 'Px1' ,
462+ threadId : 'Tx1' ,
463+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 4 } ,
464+ rawMessage : 'Node.PipelineNode.Starting' ,
465+ phase : 'starting' ,
466+ rawDetails : { task_id : 2 , node_id : 201 , name : 'NestedClick' } ,
467+ taskId : 2 ,
468+ nodeId : 201 ,
469+ name : 'NestedClick' ,
470+ } ) ,
471+ makeEvent ( {
472+ kind : 'recognition' ,
473+ seq : 5 ,
474+ ts : '2026-04-08 00:00:05.000' ,
475+ tsMs : 5 ,
476+ processId : 'Px1' ,
477+ threadId : 'Tx1' ,
478+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 5 } ,
479+ rawMessage : 'Node.Recognition.Starting' ,
480+ phase : 'starting' ,
481+ rawDetails : { task_id : 2 , reco_id : 701 , name : 'NestedClick' } ,
482+ taskId : 2 ,
483+ recoId : 701 ,
484+ name : 'NestedClick' ,
485+ } ) ,
486+ makeEvent ( {
487+ kind : 'recognition' ,
488+ seq : 6 ,
489+ ts : '2026-04-08 00:00:06.000' ,
490+ tsMs : 6 ,
491+ processId : 'Px1' ,
492+ threadId : 'Tx1' ,
493+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 6 } ,
494+ rawMessage : 'Node.Recognition.Succeeded' ,
495+ phase : 'succeeded' ,
496+ rawDetails : { task_id : 2 , reco_id : 701 , name : 'NestedClick' } ,
497+ taskId : 2 ,
498+ recoId : 701 ,
499+ name : 'NestedClick' ,
500+ } ) ,
501+ makeEvent ( {
502+ kind : 'action' ,
503+ seq : 7 ,
504+ ts : '2026-04-08 00:00:07.000' ,
505+ tsMs : 7 ,
506+ processId : 'Px1' ,
507+ threadId : 'Tx1' ,
508+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 7 } ,
509+ rawMessage : 'Node.Action.Starting' ,
510+ phase : 'starting' ,
511+ rawDetails : { task_id : 2 , action_id : 702 , name : 'NestedClick' } ,
512+ taskId : 2 ,
513+ actionId : 702 ,
514+ name : 'NestedClick' ,
515+ } ) ,
516+ makeEvent ( {
517+ kind : 'action' ,
518+ seq : 8 ,
519+ ts : '2026-04-08 00:00:08.000' ,
520+ tsMs : 8 ,
521+ processId : 'Px1' ,
522+ threadId : 'Tx1' ,
523+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 8 } ,
524+ rawMessage : 'Node.Action.Succeeded' ,
525+ phase : 'succeeded' ,
526+ rawDetails : { task_id : 2 , action_id : 702 , name : 'NestedClick' } ,
527+ taskId : 2 ,
528+ actionId : 702 ,
529+ name : 'NestedClick' ,
530+ } ) ,
531+ makeEvent ( {
532+ kind : 'wait_freezes' ,
533+ seq : 9 ,
534+ ts : '2026-04-08 00:00:09.000' ,
535+ tsMs : 9 ,
536+ processId : 'Px1' ,
537+ threadId : 'Tx1' ,
538+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 9 } ,
539+ rawMessage : 'Node.WaitFreezes.Starting' ,
540+ phase : 'starting' ,
541+ rawDetails : { task_id : 1 , wf_id : 901 , phase : 'post' , name : 'NestedClick' } ,
542+ taskId : 1 ,
543+ wfId : 901 ,
544+ waitPhase : 'post' ,
545+ name : 'NestedClick' ,
546+ } ) ,
547+ makeEvent ( {
548+ kind : 'wait_freezes' ,
549+ seq : 10 ,
550+ ts : '2026-04-08 00:00:10.000' ,
551+ tsMs : 10 ,
552+ processId : 'Px1' ,
553+ threadId : 'Tx1' ,
554+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 10 } ,
555+ rawMessage : 'Node.WaitFreezes.Succeeded' ,
556+ phase : 'succeeded' ,
557+ rawDetails : { task_id : 1 , wf_id : 901 , phase : 'post' , name : 'NestedClick' , elapsed : 15 } ,
558+ taskId : 1 ,
559+ wfId : 901 ,
560+ waitPhase : 'post' ,
561+ elapsed : 15 ,
562+ name : 'NestedClick' ,
563+ } ) ,
564+ makeEvent ( {
565+ kind : 'pipeline_node' ,
566+ seq : 11 ,
567+ ts : '2026-04-08 00:00:11.000' ,
568+ tsMs : 11 ,
569+ processId : 'Px1' ,
570+ threadId : 'Tx1' ,
571+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 11 } ,
572+ rawMessage : 'Node.PipelineNode.Succeeded' ,
573+ phase : 'succeeded' ,
574+ rawDetails : { task_id : 2 , node_id : 201 , name : 'NestedClick' } ,
575+ taskId : 2 ,
576+ nodeId : 201 ,
577+ name : 'NestedClick' ,
578+ } ) ,
579+ makeEvent ( {
580+ kind : 'action' ,
581+ seq : 12 ,
582+ ts : '2026-04-08 00:00:12.000' ,
583+ tsMs : 12 ,
584+ processId : 'Px1' ,
585+ threadId : 'Tx1' ,
586+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 12 } ,
587+ rawMessage : 'Node.Action.Succeeded' ,
588+ phase : 'succeeded' ,
589+ rawDetails : { task_id : 1 , action_id : 601 , name : 'OuterAction' } ,
590+ taskId : 1 ,
591+ actionId : 601 ,
592+ name : 'OuterAction' ,
593+ } ) ,
594+ makeEvent ( {
595+ kind : 'pipeline_node' ,
596+ seq : 13 ,
597+ ts : '2026-04-08 00:00:13.000' ,
598+ tsMs : 13 ,
599+ processId : 'Px1' ,
600+ threadId : 'Tx1' ,
601+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 13 } ,
602+ rawMessage : 'Node.PipelineNode.Succeeded' ,
603+ phase : 'succeeded' ,
604+ rawDetails : { task_id : 1 , node_id : 101 , name : 'MainNode' } ,
605+ taskId : 1 ,
606+ nodeId : 101 ,
607+ name : 'MainNode' ,
608+ } ) ,
609+ makeEvent ( {
610+ kind : 'task' ,
611+ seq : 14 ,
612+ ts : '2026-04-08 00:00:14.000' ,
613+ tsMs : 14 ,
614+ processId : 'Px1' ,
615+ threadId : 'Tx1' ,
616+ source : { sourceKey : 'maa.log' , inputIndex : 0 , line : 14 } ,
617+ rawMessage : 'Tasker.Task.Succeeded' ,
618+ phase : 'succeeded' ,
619+ rawDetails : { task_id : 1 , entry : 'Main' } ,
620+ taskId : 1 ,
621+ entry : 'Main' ,
622+ } ) ,
623+ ]
624+
625+ const trace = buildTraceTree ( events )
626+
627+ const task = trace . children [ 0 ]
628+ const pipeline = task ?. children [ 0 ]
629+ const action = pipeline ?. children [ 0 ]
630+
631+ expect ( action ?. kind ) . toBe ( 'action' )
632+ expect ( action ?. children ) . toHaveLength ( 1 )
633+
634+ const nestedPipeline = action ?. children [ 0 ]
635+ expect ( nestedPipeline ?. kind ) . toBe ( 'pipeline_node' )
636+ expect ( nestedPipeline ?. taskId ) . toBe ( 2 )
637+ expect ( nestedPipeline ?. children . map ( ( item ) => item . kind ) ) . toEqual ( [
638+ 'recognition' ,
639+ 'action' ,
640+ 'wait_freezes' ,
641+ ] )
642+ expect ( nestedPipeline ?. children [ 2 ] ?. taskId ) . toBe ( 1 )
643+ } )
644+
410645 it ( 'parents taskless foreign scopes under the active business scope from the same source' , ( ) => {
411646 const events : ProtocolEvent [ ] = [
412647 makeEvent ( {
0 commit comments