33 */
44import {
55 createAgentBlock ,
6- databaseMock ,
76 dbChainMock ,
7+ dbChainMockFns ,
88 queueTableRows ,
99 resetDbChainMock ,
1010 schemaMock ,
@@ -17,8 +17,6 @@ const mocks = vi.hoisted(() => ({
1717 saveRaw : vi . fn ( ) ,
1818} ) )
1919
20- vi . mock ( '@sim/db' , ( ) => ( { ...databaseMock , workflow : schemaMock . workflow } ) )
21-
2220vi . mock ( '@/lib/core/config/feature-flags' , ( ) => ( {
2321 isFeatureEnabled : mocks . isFeatureEnabled ,
2422} ) )
@@ -181,4 +179,28 @@ describe('agent tool Permission Mode write gate', () => {
181179 ) . rejects . toMatchObject ( { code : 'validation' } )
182180 expect ( mocks . saveRaw ) . not . toHaveBeenCalled ( )
183181 } )
182+
183+ it ( 'waits for the caller transaction lock before reading retained permissions' , async ( ) => {
184+ const state = stateWithTool (
185+ { type : 'function' , usageControlExpression : 'force' } ,
186+ { '0:agentToolUsageControl' : 'advanced' }
187+ )
188+ let releaseLock ! : ( rows : { id : string } [ ] ) => void
189+ const lock = new Promise < { id : string } [ ] > ( ( resolve ) => {
190+ releaseLock = resolve
191+ } )
192+ dbChainMockFns . for . mockReturnValueOnce ( lock )
193+
194+ const save = saveWorkflowToNormalizedTables ( 'workflow-1' , state , GOVERNANCE , dbChainMock . db )
195+ await vi . waitFor ( ( ) => expect ( dbChainMockFns . for ) . toHaveBeenCalledWith ( 'update' ) , {
196+ interval : 1 ,
197+ } )
198+ expect ( mocks . isFeatureEnabled ) . not . toHaveBeenCalled ( )
199+ expect ( mocks . saveRaw ) . not . toHaveBeenCalled ( )
200+
201+ queueTableRows ( schemaMock . workflowBlocks , [ ] )
202+ releaseLock ( [ { id : 'workflow-1' } ] )
203+ await expect ( save ) . rejects . toMatchObject ( { code : 'validation' } )
204+ expect ( mocks . saveRaw ) . not . toHaveBeenCalled ( )
205+ } )
184206} )
0 commit comments