@@ -1101,6 +1101,39 @@ describe('RemoteHandle', () => {
11011101 expect ( seqState ?. nextSendSeq ) . toBe ( 2 ) ;
11021102 } ) ;
11031103
1104+ it ( 'recovers orphan message when no seq state exists' , async ( ) => {
1105+ // Simulate crash during first enqueue: message written but NO seq state
1106+ // persisted at all. This can happen if crash occurs after setPendingMessage
1107+ // but before setRemoteStartSeq.
1108+ mockKernelStore . setPendingMessage ( mockRemoteId , 1 , '{"seq":1}' ) ;
1109+ // No seq state set - getRemoteSeqState will return undefined
1110+
1111+ // Create RemoteHandle - should scan and find orphan message at seq 1
1112+ const remote = makeRemote ( ) ;
1113+
1114+ // Next message should get seq 2 (recovered seq 1, then +1)
1115+ const promiseRRef = 'rp+3' ;
1116+ const resolutions : VatOneResolution [ ] = [
1117+ [ promiseRRef , false , { body : '"resolved value"' , slots : [ ] } ] ,
1118+ ] ;
1119+ await remote . deliverNotify ( resolutions ) ;
1120+
1121+ const sentString = vi . mocked ( mockRemoteComms . sendRemoteMessage ) . mock
1122+ . calls [ 0 ] ?. [ 1 ] ;
1123+ expect ( sentString ) . toBeDefined ( ) ;
1124+ const parsed = JSON . parse ( sentString as string ) ;
1125+ expect ( parsed . seq ) . toBe ( 2 ) ;
1126+
1127+ // Verify state is correct: seq state recovered and 2 pending messages
1128+ const seqState = mockKernelStore . getRemoteSeqState ( mockRemoteId ) ;
1129+ expect ( seqState ?. startSeq ) . toBe ( 1 ) ;
1130+ expect ( seqState ?. nextSendSeq ) . toBe ( 2 ) ;
1131+ // Original orphan message still exists
1132+ expect ( mockKernelStore . getPendingMessage ( mockRemoteId , 1 ) ) . toBe (
1133+ '{"seq":1}' ,
1134+ ) ;
1135+ } ) ;
1136+
11041137 it ( 'ignores orphan messages (seq < startSeq) on recovery' , ( ) => {
11051138 // Simulate crash during ACK: startSeq updated but message not deleted
11061139 mockKernelStore . setRemoteNextSendSeq ( mockRemoteId , 3 ) ;
0 commit comments