@@ -504,3 +504,41 @@ func Test_ErrorRemovesPartialMessage(t *testing.T) {
504504 assert .Equal (t , screentracker .ConversationRoleUser , messages [0 ].Role )
505505 assert .Equal (t , "test" , messages [0 ].Message )
506506}
507+
508+ func Test_LateChunkAfterError_DoesNotCorruptUserMessage (t * testing.T ) {
509+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
510+ defer cancel ()
511+
512+ mClock := quartz .NewMock (t )
513+ mock := newMockAgentIO ()
514+ emitter := newMockEmitter ()
515+ started , done := mock .BlockWrite ()
516+
517+ conv := acpio .NewACPConversation (ctx , mock , nil , nil , emitter , mClock )
518+ conv .Start (ctx )
519+
520+ // Given: a send that fails with an error, removing the agent placeholder
521+ err := conv .Send (screentracker.MessagePartText {Content : "hello" })
522+ require .NoError (t , err )
523+ <- started
524+
525+ mock .mu .Lock ()
526+ mock .writeErr = assert .AnError
527+ mock .mu .Unlock ()
528+ close (done )
529+
530+ emitter .WaitForStatus (ctx , t , screentracker .ConversationStatusStable )
531+
532+ messages := conv .Messages ()
533+ require .Len (t , messages , 1 , "agent placeholder should be removed after error" )
534+ assert .Equal (t , "hello" , messages [0 ].Message )
535+
536+ // When: a late chunk arrives after the prompt has already errored
537+ mock .SimulateChunks ("late response data" )
538+
539+ // Then: the user message is not corrupted
540+ messages = conv .Messages ()
541+ require .Len (t , messages , 1 , "no new messages should appear from a late chunk" )
542+ assert .Equal (t , "hello" , messages [0 ].Message )
543+ assert .Equal (t , screentracker .ConversationRoleUser , messages [0 ].Role )
544+ }
0 commit comments