@@ -13,6 +13,7 @@ const finalizeSlackPreviewEditMock = vi.fn(async () => {});
1313const postMessageMock = vi . fn ( async ( ) => ( { ok : true , ts : "171234.999" } ) ) ;
1414const chatUpdateMock = vi . fn ( async ( ) => ( { ok : true , ts : "171234.999" } ) ) ;
1515const recordInboundSessionMock = vi . fn ( async ( ) => undefined ) ;
16+ const recordSlackThreadParticipationMock = vi . fn ( ) ;
1617const updateLastRouteMock = vi . fn ( async ( ) => { } ) ;
1718const appendSlackStreamMock = vi . fn ( async ( ) => { } ) ;
1819const startSlackStreamMock = vi . fn ( async ( ) => ( {
@@ -830,7 +831,7 @@ vi.mock("../../limits.js", () => ({
830831} ) ) ;
831832
832833vi . mock ( "../../sent-thread-cache.js" , ( ) => ( {
833- recordSlackThreadParticipation : ( ) => { } ,
834+ recordSlackThreadParticipation : recordSlackThreadParticipationMock ,
834835} ) ) ;
835836
836837vi . mock ( "../../stream-mode.js" , ( ) => ( {
@@ -1228,6 +1229,7 @@ describe("dispatchPreparedSlackMessage preview fallback", () => {
12281229 postMessageMock . mockClear ( ) ;
12291230 chatUpdateMock . mockClear ( ) ;
12301231 recordInboundSessionMock . mockReset ( ) ;
1232+ recordSlackThreadParticipationMock . mockReset ( ) ;
12311233 updateLastRouteMock . mockReset ( ) ;
12321234 appendSlackStreamMock . mockReset ( ) ;
12331235 startSlackStreamMock . mockReset ( ) ;
@@ -3506,6 +3508,67 @@ describe("dispatchPreparedSlackMessage preview fallback", () => {
35063508 expect ( session . stopped ) . toBe ( true ) ;
35073509 } ) ;
35083510
3511+ it ( "routes pending native stream text through chunked sender for unexpected finalize failures" , async ( ) => {
3512+ mockedNativeStreaming = true ;
3513+ const session = {
3514+ channel : "C123" ,
3515+ threadTs : THREAD_TS ,
3516+ stopped : false ,
3517+ delivered : false ,
3518+ pendingText : FINAL_REPLY_TEXT ,
3519+ } ;
3520+ startSlackStreamMock . mockResolvedValueOnce ( session ) ;
3521+ stopSlackStreamMock . mockRejectedValueOnce (
3522+ new TestSlackStreamNotDeliveredError (
3523+ FINAL_REPLY_TEXT ,
3524+ "method_not_supported_for_channel_type" ,
3525+ ) ,
3526+ ) ;
3527+
3528+ await dispatchPreparedSlackMessage ( createPreparedSlackMessage ( ) ) ;
3529+
3530+ expect ( postMessageMock ) . not . toHaveBeenCalled ( ) ;
3531+ expect ( deliverRepliesMock ) . toHaveBeenCalledTimes ( 1 ) ;
3532+ expect ( deliverRepliesMock ) . toHaveBeenCalledWith (
3533+ expect . objectContaining ( {
3534+ replyThreadTs : THREAD_TS ,
3535+ replies : [ expect . objectContaining ( { text : FINAL_REPLY_TEXT } ) ] ,
3536+ } ) ,
3537+ ) ;
3538+ expect ( session . stopped ) . toBe ( true ) ;
3539+ } ) ;
3540+
3541+ it ( "fails dispatch when an unexpected finalize fallback cannot deliver a buffered tail" , async ( ) => {
3542+ mockedNativeStreaming = true ;
3543+ const session = {
3544+ channel : "C123" ,
3545+ threadTs : THREAD_TS ,
3546+ stopped : false ,
3547+ delivered : true ,
3548+ pendingText : "buffered tail" ,
3549+ } ;
3550+ startSlackStreamMock . mockResolvedValueOnce ( session ) ;
3551+ stopSlackStreamMock . mockRejectedValueOnce (
3552+ new TestSlackStreamNotDeliveredError (
3553+ "buffered tail" ,
3554+ "method_not_supported_for_channel_type" ,
3555+ ) ,
3556+ ) ;
3557+ deliverRepliesMock . mockRejectedValueOnce ( new Error ( "fallback send failed" ) ) ;
3558+
3559+ await expect ( dispatchPreparedSlackMessage ( createPreparedSlackMessage ( ) ) ) . rejects . toThrowError (
3560+ "slack-stream not delivered: method_not_supported_for_channel_type" ,
3561+ ) ;
3562+
3563+ expectDeliverReplyCall ( 0 , "buffered tail" ) ;
3564+ expect ( recordSlackThreadParticipationMock ) . toHaveBeenCalledWith (
3565+ expect . any ( String ) ,
3566+ "C123" ,
3567+ THREAD_TS ,
3568+ expect . any ( Object ) ,
3569+ ) ;
3570+ } ) ;
3571+
35093572 it ( "routes all pending native stream text through chunked sender when an append flush fails" , async ( ) => {
35103573 mockedNativeStreaming = true ;
35113574 mockedDispatchSequence = [
0 commit comments