Если вы проверите тему плагина @angus Custom Wizard Plugin как анонимный пользователь в режиме вложенных ответов: https://meta.discourse.org/n/-/73345.json?page=0&sort=old
/n/-/73345.json?page=0&sort=old возвращает 20 корневых сообщений, и каждое из них является удалённым заполнителем — пустое cooked, нет автора, total_descendant_count: 0. Таким образом, вся первая страница состоит из пустых строк «удалено».
Плоский вид тех же сообщений ничего не показывает (пост #2 просто пропускает к связанным темам), поэтому они там корректно скрыты. Вложенный вид сохраняет их и учитывает в количестве сообщений на странице, что и вызывает несоответствие.
Похоже, что загрузчик дерева намеренно загружает удалённые сообщения (чтобы отображать удалённый родительский пост, если у него ещё есть активные ответы), но он также сохраняет удалённые сообщения, у которых больше нет видимых ответов. В теме, где ранние ответы были удалены, в итоге вы получаете целую страницу пустых заполнителей вместо реального контента.
Настройка определённо включена — endpoint вернул 200 вместо 404.
Виновником, похоже, является apply_visibility в NestedReplies::TreeLoader — scope.unscope(where: :deleted_at) загружает в дерево все удалённые сообщения. Это имеет смысл для удалённого родительского поста, у которого ещё есть активные ответы, но это также сохраняет удалённые конечные узлы и полностью удалённые ветви, которые занимают места в окне ROOTS_PER_PAGE (и учитываются в has_more_roots).
Для не-стаффа, я думаю, нужно отбрасывать удалённый пост, если у него нет хотя бы одного не удалённого потомка — сохранять его только тогда, когда его видимое total_descendant_count > 0. NestedViewPostStat уже исключает удалённые/шепотные потомки из этого подсчёта, поэтому дополнительных запросов не требуется.
Это нужно применить в трёх местах, которые формируют страницу, чтобы не получать неполные страницы: root_posts_scope, batch_preload_tree и часть заполнения страницы / has_more_roots. Путь для стаффа остаётся без изменений для восстановления.

