ok, this rails script will act as a global “mark all as read” and force the unread count back to 0 for all users, so unfortunately it will clear any legitimate unread counts in addition to any phantom unreads. we can do this with a sql command in rails. but note that it doesn’t fix the root bug. also, good idea if you have a recent backup handy, but i tested this on my dev forum and it worked.
cd /var/discourse
./launcher enter app
rails c
paste the whole following block and hit enter
sql = <<~SQL
UPDATE topic_users
SET last_read_post_number = topics.highest_post_number
FROM topics
WHERE topics.id = topic_users.topic_id
AND COALESCE(topic_users.last_read_post_number, 0) < topics.highest_post_number
AND topic_users.notification_level IN (2, 3, 4) -- Tracking, Watching, Watching First Post
SQL
# run the update
result = ActiveRecord::Base.connection.execute(sql)
puts "Successfully cleared #{result.cmd_tuples} unread topics site-wide."
# force client browsers to drop their cached state and sync with the database
MessageBus.publish("/topic-tracking-state", { clear: true })
users may have to hard refresh to see the cleared unread state.