@@ -56,6 +56,13 @@ const unusedTranscripts = {
5656 } ,
5757} ;
5858
59+ const noMessageExecutions = async ( ) => ( {
60+ resolutions : [ ] as Array <
61+ | { messageId : string ; state : 'pending' }
62+ | { messageId : string ; state : 'owned' ; turnId : string ; runId : string }
63+ > ,
64+ } ) ;
65+
5966function transcriptsWith ( messages : readonly StoredMessage [ ] ) {
6067 return {
6168 open : async ( sessionId : string , handler : ( batch : DesktopTranscriptBatch ) => void ) => {
@@ -151,6 +158,7 @@ test('projects the durable Coordination transcript into the WorkHub conversation
151158 delegationId : 'payments-delegation' ,
152159 targetSessionId : 'payments' ,
153160 targetSessionName : 'Payments' ,
161+ targetMessageId : 'payments-message' ,
154162 targetTurnId : 'payments-turn' ,
155163 feedbackState : 'accepted' ,
156164 } ,
@@ -294,6 +302,7 @@ test('desktop adapter rebuilds recent turns from the Session transcript and clos
294302 sessions : {
295303 list : async ( ) => [ ] ,
296304 listTurns : async ( ) => [ ] ,
305+ queryMessageExecutions : noMessageExecutions ,
297306 create : async ( ) => {
298307 throw new Error ( 'not used' ) ;
299308 } ,
@@ -369,6 +378,7 @@ test('desktop adapter cancels an unavailable transcript without hiding ready Ses
369378 sessions : {
370379 list : async ( ) => [ ] ,
371380 listTurns : async ( ) => [ ] ,
381+ queryMessageExecutions : noMessageExecutions ,
372382 create : async ( ) => { throw new Error ( 'not used' ) ; } ,
373383 send : async ( ) => { throw new Error ( 'not used' ) ; } ,
374384 stop : async ( ) => { } ,
@@ -451,6 +461,7 @@ test('desktop adapter projects Session catalog facts without owning copies', asy
451461 sessions : {
452462 list : async ( ) => source ,
453463 listTurns : async ( ) => [ ] ,
464+ queryMessageExecutions : noMessageExecutions ,
454465 create : async ( ) => {
455466 throw new Error ( 'not used' ) ;
456467 } ,
@@ -509,7 +520,7 @@ test('desktop adapter projects Session catalog facts without owning copies', asy
509520 ] ) ;
510521} ) ;
511522
512- test ( 'desktop adapter rebuilds delegation feedback from the exact authoritative Turn' , async ( ) => {
523+ test ( 'desktop adapter rebuilds delegation feedback from the Message-owned execution Turn' , async ( ) => {
513524 const sessions = [
514525 desktopSession ( 'accepted' ) ,
515526 desktopSession ( 'running' , { status : 'running' , runningTurnIds : [ 'turn-running' ] } ) ,
@@ -544,6 +555,18 @@ test('desktop adapter rebuilds delegation feedback from the exact authoritative
544555 if ( sessionId === 'recovering' ) throw new Error ( 'Host is recovering' ) ;
545556 return turns . get ( sessionId ) ?? [ ] ;
546557 } ,
558+ queryMessageExecutions : async ( sessionId , messageIds ) => ( {
559+ resolutions : sessionId === 'accepted'
560+ ? messageIds . map ( ( messageId ) => ( { messageId, state : 'pending' as const } ) )
561+ : sessionId === 'recovering'
562+ ? [ ]
563+ : messageIds . map ( ( messageId ) => ( {
564+ messageId,
565+ state : 'owned' as const ,
566+ turnId : `turn-${ sessionId } ` ,
567+ runId : `run-${ sessionId } ` ,
568+ } ) ) ,
569+ } ) ,
547570 create : async ( ) => { throw new Error ( 'not used' ) ; } ,
548571 send : async ( ) => { throw new Error ( 'not used' ) ; } ,
549572 stop : async ( ) => { } ,
@@ -563,6 +586,7 @@ test('desktop adapter rebuilds delegation feedback from the exact authoritative
563586 ] . map ( ( [ targetSessionId , targetTurnId ] ) => ( {
564587 delegationId : `delegation-${ targetSessionId } ` ,
565588 targetSessionId : targetSessionId ! ,
589+ targetMessageId : `message-${ targetSessionId } ` ,
566590 targetTurnId : targetTurnId ! ,
567591 } ) ) ;
568592
@@ -579,6 +603,63 @@ test('desktop adapter rebuilds delegation feedback from the exact authoritative
579603 ] ) ;
580604} ) ;
581605
606+ test ( 'desktop adapter follows a delegated Message into its successor Turn' , async ( ) => {
607+ const targetSessionId = desktopSessionKey ( { hostId : 'local-host' , sessionId : 'payments' } ) ;
608+ const adapter = createDesktopWorkHubSessionPort ( {
609+ transcripts : transcriptsWith ( [ {
610+ type : 'user' ,
611+ id : 'payment-message' ,
612+ turnId : 'successor-turn' ,
613+ ts : 2 ,
614+ text : 'Continue payment recovery' ,
615+ steeringEventId : 'payment-message' ,
616+ } ] ) ,
617+ sessions : {
618+ list : async ( ) => [ desktopSession ( targetSessionId , {
619+ status : 'running' ,
620+ runningTurnIds : [ 'successor-turn' ] ,
621+ } ) ] ,
622+ listTurns : async ( ) => [
623+ {
624+ turnId : 'admission-turn' ,
625+ status : 'completed' ,
626+ statusSource : 'recorded' ,
627+ } ,
628+ {
629+ turnId : 'successor-turn' ,
630+ status : 'running' ,
631+ statusSource : 'recorded' ,
632+ } ,
633+ ] ,
634+ queryMessageExecutions : async ( _sessionId , messageIds ) => ( {
635+ resolutions : messageIds . map ( ( messageId ) => ( {
636+ messageId,
637+ state : 'owned' as const ,
638+ turnId : 'successor-turn' ,
639+ runId : 'successor-run' ,
640+ } ) ) ,
641+ } ) ,
642+ create : async ( ) => { throw new Error ( 'not used' ) ; } ,
643+ send : async ( ) => { throw new Error ( 'not used' ) ; } ,
644+ stop : async ( ) => { } ,
645+ subscribeChanges : ( ) => ( ) => { } ,
646+ } ,
647+ projectName : ( ) => 'Maka' ,
648+ newTurnId : ( ) => 'unused' ,
649+ } ) ;
650+
651+ const references = [ {
652+ delegationId : 'payment-delegation' ,
653+ targetSessionId,
654+ targetTurnId : 'admission-turn' ,
655+ targetMessageId : 'payment-message' ,
656+ } ] ;
657+ assert . deepEqual ( await adapter . delegationFeedback ( references ) , [ {
658+ delegationId : 'payment-delegation' ,
659+ state : 'running' ,
660+ } ] ) ;
661+ } ) ;
662+
582663test ( 'desktop adapter preserves per-Host catalog coverage for ownership reconciliation' , async ( ) => {
583664 const localSessionId = desktopSessionKey ( { hostId : 'local-host' , sessionId : 'local' } ) ;
584665 const adapter = createDesktopWorkHubSessionPort ( {
@@ -590,6 +671,7 @@ test('desktop adapter preserves per-Host catalog coverage for ownership reconcil
590671 completeHostIds : [ 'local-host' ] ,
591672 } ) ,
592673 listTurns : async ( ) => [ ] ,
674+ queryMessageExecutions : noMessageExecutions ,
593675 create : async ( ) => { throw new Error ( 'not used' ) ; } ,
594676 send : async ( ) => { throw new Error ( 'not used' ) ; } ,
595677 stop : async ( ) => { } ,
@@ -619,6 +701,7 @@ test('desktop adapter delegates create, send, and invalidation to Session APIs',
619701 runningTurnIds : [ 'turn-new' ] ,
620702 } ) ] ,
621703 listTurns : async ( ) => [ ] ,
704+ queryMessageExecutions : noMessageExecutions ,
622705 create : async ( input ) => {
623706 calls . push ( [ 'create' , input ] ) ;
624707 return desktopSession ( 'created' , { name : input . name } ) ;
@@ -667,6 +750,7 @@ test('desktop adapter preserves when Session delivery steered an existing root T
667750 sessions : {
668751 list : async ( ) => [ ] ,
669752 listTurns : async ( ) => [ ] ,
753+ queryMessageExecutions : noMessageExecutions ,
670754 create : async ( ) => {
671755 throw new Error ( 'not used' ) ;
672756 } ,
@@ -699,6 +783,7 @@ test('desktop adapter distinguishes definite rejection from an unknown delivery
699783 sessions : {
700784 list : async ( ) => [ ] ,
701785 listTurns : async ( ) => [ ] ,
786+ queryMessageExecutions : noMessageExecutions ,
702787 create : async ( ) => { throw new Error ( 'not used' ) ; } ,
703788 send : async ( ) => {
704789 if ( outcome === 'throw' ) throw new Error ( 'transport disconnected' ) ;
@@ -792,6 +877,7 @@ test('desktop adapter reconciles lost replies from authoritative transcript iden
792877 sessions : {
793878 list : async ( ) => [ ] ,
794879 listTurns : async ( ) => [ ] ,
880+ queryMessageExecutions : noMessageExecutions ,
795881 create : async ( ) => { throw new Error ( 'not used' ) ; } ,
796882 send : async ( ) => { throw new Error ( 'not used' ) ; } ,
797883 stop : async ( ) => { } ,
@@ -818,6 +904,7 @@ test('desktop adapter binds stop to the root Turn owned by the WorkHub submissio
818904 sessions : {
819905 list : async ( ) => [ ] ,
820906 listTurns : async ( ) => [ ] ,
907+ queryMessageExecutions : noMessageExecutions ,
821908 create : async ( ) => {
822909 throw new Error ( 'not used' ) ;
823910 } ,
@@ -855,6 +942,7 @@ test('desktop adapter derives stable origin evidence from the existing Session l
855942 { userPromptPreview : '把风险按高、中、低分组' } ,
856943 ] ;
857944 } ,
945+ queryMessageExecutions : noMessageExecutions ,
858946 create : async ( ) => {
859947 throw new Error ( 'not used' ) ;
860948 } ,
0 commit comments