Whenever NodeBB sends stuff to Discourse, it ends up posting twice.
I have a theory that this is due to our category syncing logic which is based off of 1b12.
NodeBB federates both an Announce(Note) and Announce(Create(Note)), with the former being legacy usage because Mastodon does not support the latter (I think!!) — or maybe it’s because I’m sending a Create(Note) as well.
This might be leading to a race condition on your end where both activities begin processing but pass the “have I seen this before?” check since the object technically is not there yet.
FWIW NodeBB guards against this in our notes.assert method by using something like a lockfile, so when parallel activities are received, one fails since the other started first and locked the other one out.
Double posts happen with federated content not just from NodeBB. The first post will indicate it came from the origin, e.g. mastodon.social, with a blue icon. The second post will indicate it was published via socialhub.activitypub.rocks, with a green icon. I suspect that Discourse is including its own reshares in threads.