As written, yes. The call to try await merger.processChanges(forCounter: counter) will suspend that loop for as long as it takes processChanges to return. Until processChanges has run to completion (including anything that it itself awaits on, such as Task.sleep), the next iteration will not happen.
@lukasa Thanks a lot for clear explanation as to why it works.
In the real world, the next challenge for me is to ensure everything passed to processChanges is sendable and there is that clear separation and nothing crosses concurrency boundaries (which I often encounter)