wrapTurboModule closes a call record as soon as the wrapped method returns, and only defers when the return value is thenable. Bridge methods that complete via success/failure callbacks — the common async shape on the Old Architecture, and still used by some TurboModules — return undefined, so they're recorded as sync with near-zero duration. Consequences: durations in turbo_module.* span attributes and the periodic aggregate are wrong for those methods, and native.turbo_module slow-call breadcrumbs never fire for them.
Possible fix: detect trailing function arguments, wrap them, and close the record when the callback fires (with a cap/timeout so a never-invoked callback can't pin the record). Needs care around methods that take non-completion function args.
Found by Cursor Bugbot on #6504.
wrapTurboModulecloses a call record as soon as the wrapped method returns, and only defers when the return value is thenable. Bridge methods that complete via success/failure callbacks — the common async shape on the Old Architecture, and still used by some TurboModules — return undefined, so they're recorded as sync with near-zero duration. Consequences: durations in turbo_module.* span attributes and the periodic aggregate are wrong for those methods, and native.turbo_module slow-call breadcrumbs never fire for them.Possible fix: detect trailing function arguments, wrap them, and close the record when the callback fires (with a cap/timeout so a never-invoked callback can't pin the record). Needs care around methods that take non-completion function args.
Found by Cursor Bugbot on #6504.