@@ -160,6 +160,7 @@ function makeHarness(
160160 }
161161 readFileFailuresBeforeSuccess ?: number
162162 failReadFile ?: boolean
163+ readFileError ?: Error
163164 sendDelayMs ?: number
164165 onSendStart ?: ( activeSends : number ) => void
165166 waitForDeliveryNeverSettles ?: boolean
@@ -205,6 +206,7 @@ function makeHarness(
205206 if ( options . readFileFailuresBeforeSuccess && readFileAttempts <= options . readFileFailuresBeforeSuccess ) {
206207 throw new Error ( 'remote file not ready' )
207208 }
209+ if ( options . readFileError ) throw options . readFileError
208210 if ( options . failReadFile ) throw new Error ( 'remote file not ready' )
209211 return options . readFileResponse ?.( workspaceId , path ) ?? {
210212 path,
@@ -606,25 +608,16 @@ test('integration events watch selected relayfile mount paths', async () => {
606608
607609 assert . deepEqual ( harness . subscribeCalls [ 0 ] . globs , [
608610 '/slack/channels/C123ABC/**' ,
609- '/slack/channels/C123ABC__proj-cloud/**' ,
610- '/slack/channels/D*/**' ,
611- '/slack/dms/*/**' ,
612- '/slack/users/*/messages/**'
611+ '/slack/channels/C123ABC__proj-cloud/**'
613612 ] )
614613 assert . deepEqual ( harness . subscribeCalls [ 0 ] . options ?. pathScope , [
615614 '/slack/channels/C123ABC/**' ,
616- '/slack/channels/C123ABC__proj-cloud/**' ,
617- '/slack/channels/D*/**' ,
618- '/slack/dms/*/**' ,
619- '/slack/users/*/messages/**'
615+ '/slack/channels/C123ABC__proj-cloud/**'
620616 ] )
621617 assert . equal ( harness . subscribeCalls [ 0 ] . options ?. from , 'legacy' )
622618 assert . deepEqual ( integrationSubscriptionSummaries ( [ slackIntegration ] ) [ 0 ] . watches , [
623619 '.integrations/slack/channels/C123ABC/**' ,
624- '.integrations/slack/channels/C123ABC__proj-cloud/**' ,
625- '.integrations/slack/channels/D*/**' ,
626- '.integrations/slack/dms/*/**' ,
627- '.integrations/slack/users/*/messages/**'
620+ '.integrations/slack/channels/C123ABC__proj-cloud/**'
628621 ] )
629622
630623 const selectedPath = '/slack/channels/C123ABC__proj-cloud/messages/1780668000_000000/meta.json'
@@ -669,8 +662,7 @@ test('integration events watch selected relayfile mount paths', async () => {
669662 assert . deepEqual ( harness . sent , [ ] )
670663
671664 await harness . emit ( changeEvent ( '/slack/channels/D123ABC/messages/1780668180_000000/meta.json' , 'slack' ) )
672- await waitForSent ( harness , 1 )
673- assert . deepEqual ( harness . sent . map ( ( message ) => message . input . to ) , [ 'alice' ] )
665+ assert . deepEqual ( harness . sent , [ ] )
674666} )
675667
676668test ( 'slack raw-id and slug alias paths with distinct revisions inject once per logical message' , async ( ) => {
@@ -800,7 +792,7 @@ test('slack raw-id and slug alias duplicates suppress when one context read is s
800792 assert . match ( harness . sent [ 0 ] . input . text , / M e s s a g e : \n r e a d a b l e S l a c k m e s s a g e / u)
801793} )
802794
803- test ( 'slack edits after a blind alias claim still inject once the content changes ' , async ( ) => {
795+ test ( 'slack raw-id event resolves context through mounted slug alias ' , async ( ) => {
804796 let messageText = 'original Slack message'
805797 const harness = makeHarness ( [ 'alice' ] , {
806798 readFileResponse : ( _workspaceId , path ) => {
@@ -827,8 +819,8 @@ test('slack edits after a blind alias claim still inject once the content change
827819 ] )
828820 } )
829821
830- // Raw-id copy first: every targeted read fails and the expanded event only
831- // carries the sparse relayfile pointer, so the injection is blind .
822+ // Raw-id copy first: the raw targeted read fails, then the bridge retries the
823+ // selected mounted slug alias so the injection has usable context .
832824 await harness . emit ( {
833825 ...changeEvent (
834826 '/slack/channels/C123ABC/messages/1780668000_000000/meta.json' ,
@@ -846,10 +838,21 @@ test('slack edits after a blind alias claim still inject once the content change
846838 } as ChangeEvent )
847839 await waitForSent ( harness , 1 , 2_500 )
848840 assert . equal ( harness . sent . length , 1 )
849- assert . match ( harness . sent [ 0 ] . input . text , / M e s s a g e : u n a v a i l a b l e ; t a r g e t e d c o n t e x t r e a d d i d n o t r e t u r n c o n t e n t \. / u)
841+ assert . match ( harness . sent [ 0 ] . input . text , / M e s s a g e : \n o r i g i n a l S l a c k m e s s a g e / u)
842+ assert . match ( harness . sent [ 0 ] . input . text , / P a t h : \. i n t e g r a t i o n s \/ s l a c k \/ c h a n n e l s \/ C 1 2 3 A B C _ _ p r o j - c l o u d \/ m e s s a g e s \/ 1 7 8 0 6 6 8 0 0 0 _ 0 0 0 0 0 0 \/ m e t a \. j s o n / u)
843+ assert . deepEqual ( harness . readFileCalls . slice ( 0 , 2 ) , [
844+ {
845+ workspaceId : 'workspace-id' ,
846+ path : '/slack/channels/C123ABC/messages/1780668000_000000/meta.json'
847+ } ,
848+ {
849+ workspaceId : 'workspace-id' ,
850+ path : '/slack/channels/C123ABC__proj-cloud/messages/1780668000_000000/meta.json'
851+ }
852+ ] )
850853
851- // The slug alias copy of the same record carries content: suppressed as a
852- // duplicate, but the claim learns the content hash .
854+ // The slug alias copy of the same record is now a duplicate of the
855+ // content-bearing raw delivery .
853856 await harness . emit ( changeEvent (
854857 '/slack/channels/C123ABC__proj-cloud/messages/1780668000_000000/meta.json' ,
855858 'slack' ,
@@ -1052,7 +1055,7 @@ test('historical download subscriptions can receive older remote events', async
10521055 assert . deepEqual ( harness . sent . map ( ( message ) => message . input . to ) , [ 'alice' ] )
10531056} )
10541057
1055- test ( 'slack direct message event scope can be disabled ' , async ( ) => {
1058+ test ( 'slack direct message event scope is opt-in ' , async ( ) => {
10561059 const harness = makeHarness ( )
10571060 const slackIntegration = integration ( {
10581061 provider : 'slack' ,
@@ -1173,11 +1176,17 @@ test('slack context falls back to expanded event data when targeted remote previ
11731176 assert . match ( harness . sent [ 0 ] . input . text , / S l a c k m e s s a g e e v e n t / u)
11741177 assert . match ( harness . sent [ 0 ] . input . text , / A u t h o r : K h a l i q / u)
11751178 assert . match ( harness . sent [ 0 ] . input . text , / M e s s a g e : \n e x p a n d e d S l a c k c o n t e x t / u)
1176- assert . equal ( harness . readFileCalls . length , 4 )
1177- assert . deepEqual ( harness . readFileCalls [ 0 ] , {
1178- workspaceId : 'workspace-id' ,
1179- path : messagePath
1180- } )
1179+ assert . equal ( harness . readFileCalls . length , 8 )
1180+ assert . deepEqual ( harness . readFileCalls . slice ( 0 , 2 ) , [
1181+ {
1182+ workspaceId : 'workspace-id' ,
1183+ path : messagePath
1184+ } ,
1185+ {
1186+ workspaceId : 'workspace-id' ,
1187+ path : '/slack/channels/C123ABC/messages/1780668000_000000/meta.json'
1188+ }
1189+ ] )
11811190 assert . equal ( ( harness . sent [ 0 ] . input . data ?. contextPreview as { kind ?: string } | undefined ) ?. kind , 'text' )
11821191 assert . equal ( ( harness . sent [ 0 ] . input . data ?. contextPreview as { content ?: string } | undefined ) ?. content , undefined )
11831192} )
@@ -1193,7 +1202,7 @@ test('slack context retries targeted remote preview before falling back to spars
11931202 integrationId : 'slack-1' ,
11941203 mountPaths : [ '/slack/channels/C123ABC__proj-cloud' ] ,
11951204 downloadHistoricalData : false ,
1196- scope : { notifyAgents : [ 'alice' ] }
1205+ scope : { listenDms : true , notifyAgents : [ 'alice' ] }
11971206 } )
11981207 ] )
11991208 } )
@@ -1217,6 +1226,45 @@ test('slack context retries targeted remote preview before falling back to spars
12171226 assert . doesNotMatch ( harness . sent [ 0 ] . input . text , / " d e l e t e d " : f a l s e / u)
12181227} )
12191228
1229+ test ( 'slack context stops targeted remote preview retries on auth failures' , async ( ) => {
1230+ const error = new Error ( 'http 403 forbidden' ) as Error & { status : number }
1231+ error . status = 403
1232+ const harness = makeHarness ( [ 'alice' ] , { readFileError : error } )
1233+ const messagePath = '/slack/channels/C123ABC__proj-cloud/messages/1780668000_000000/meta.json'
1234+
1235+ await withMockedNow ( '2026-06-05T14:00:00.000Z' , async ( ) => {
1236+ await harness . bridge . reconcile ( 'project-1' , [
1237+ integration ( {
1238+ provider : 'slack' ,
1239+ integrationId : 'slack-1' ,
1240+ mountPaths : [ '/slack/channels/C123ABC__proj-cloud' ] ,
1241+ downloadHistoricalData : false ,
1242+ scope : { notifyAgents : [ 'alice' ] }
1243+ } )
1244+ ] )
1245+ } )
1246+
1247+ await harness . emit ( {
1248+ ...changeEvent ( messagePath , 'slack' ) ,
1249+ expand : async ( ) => ( {
1250+ level : 'full' ,
1251+ path : messagePath ,
1252+ data : {
1253+ text : 'expanded Slack context'
1254+ }
1255+ } )
1256+ } as ChangeEvent )
1257+ await waitForSent ( harness , 1 , 2_500 )
1258+
1259+ assert . deepEqual ( harness . readFileCalls , [
1260+ {
1261+ workspaceId : 'workspace-id' ,
1262+ path : messagePath
1263+ }
1264+ ] )
1265+ assert . match ( harness . sent [ 0 ] . input . text , / M e s s a g e : \n e x p a n d e d S l a c k c o n t e x t / u)
1266+ } )
1267+
12201268test ( 'slack context does not inject sparse relayfile pointer fallback as message content' , async ( ) => {
12211269 const harness = makeHarness ( [ 'alice' ] , { failReadFile : true } )
12221270 const messagePath = '/slack/channels/D123ABC/messages/1780668000_000000/meta.json'
@@ -1228,7 +1276,7 @@ test('slack context does not inject sparse relayfile pointer fallback as message
12281276 integrationId : 'slack-1' ,
12291277 mountPaths : [ '/slack/channels/C123ABC__proj-cloud' ] ,
12301278 downloadHistoricalData : false ,
1231- scope : { notifyAgents : [ 'alice' ] }
1279+ scope : { listenDms : true , notifyAgents : [ 'alice' ] }
12321280 } )
12331281 ] )
12341282 } )
@@ -1600,16 +1648,10 @@ test('integration events preserve discovery mount paths', async () => {
16001648 await harness . bridge . reconcile ( 'project-1' , [ slackIntegration ] )
16011649
16021650 assert . deepEqual ( harness . subscribeCalls [ 0 ] . globs , [
1603- '/discovery/slack/**' ,
1604- '/slack/channels/D*/**' ,
1605- '/slack/dms/*/**' ,
1606- '/slack/users/*/messages/**'
1651+ '/discovery/slack/**'
16071652 ] )
16081653 assert . deepEqual ( integrationSubscriptionSummaries ( [ slackIntegration ] ) [ 0 ] . watches , [
1609- '.integrations/discovery/slack/**' ,
1610- '.integrations/slack/channels/D*/**' ,
1611- '.integrations/slack/dms/*/**' ,
1612- '.integrations/slack/users/*/messages/**'
1654+ '.integrations/discovery/slack/**'
16131655 ] )
16141656
16151657 await harness . emit ( changeEvent ( '/discovery/slack/actions/create-message/.schema.json' , 'slack' ) )
0 commit comments