当可审核项每个只有一个标记时,Score_to_hide_post 变为 0

摘要

score_to_hide_post 可以被驱动到 0,因为后台作业 Jobs::ReviewablePriorities 在百分位数查询返回空行时,会将 priority_#{priorities[:high]} 写入为 0。该作业在 reviewable_count >= 15 时触发,但百分位数计算仅包括满足 HAVING COUNT(*) >= :target_count(其中 target_count 通常为 2)的 reviewables。如果大多数 reviewables 只有一个标记,百分位数子查询将不返回任何内容 → high 变为 0score_to_hide_post = ((high * ratio) * scale).truncate(2) 计算结果为 0。这会导致隐藏阈值塌陷为零并产生不正确的隐藏行为。


来源(相关代码/事实)

  • score_to_hide_post 通过以下方式计算:
score_to_hide_post = ((high.to_f * ratio) * scale).truncate(2)
  • high 从插件存储中读取:
PluginStore.get("reviewables", "priority_#{priorities[:high]}")
  • 该插件存储条目由 Jobs::ReviewablePriorities(系统作业)写入。
    该作业运行时:
reviewable_count = Reviewable.approved.where("score > ?", min_priority_threshold).count
return if reviewable_count < self.class.min_reviewables

其中 self.class.min_reviewables15

  • 作业使用 SQL 计算 high
SELECT COALESCE(PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY score), 0.0) AS medium,
       COALESCE(PERCENTILE_DISC(0.85) WITHIN GROUP (ORDER BY score), 0.0) AS high
FROM (
  SELECT r.score
  FROM reviewables AS r
  INNER JOIN reviewable_scores AS rs ON rs.reviewable_id = r.id
  WHERE r.score > :min_priority AND r.status = 1
  GROUP BY r.id
  HAVING COUNT(*) >= :target_count
) AS x

其中 :target_count 通常为 2


根本原因

两个独立的阈值共同造成了一个差距:

  1. 作业在存在至少 min_reviewables(15)个高于 min_priority_threshold 的 reviewables 时触发——这是一个粗略的计数,忽略了 :target_count 要求。
  2. 但产生 high百分位数计算仅包括满足 COUNT(*) >= :target_count(即至少有 2 个 reviewable_scores)的 reviewables。如果许多 reviewables 每个只有一个标记,子查询将不返回任何行,百分位数将返回默认值 0.0

因此,作业可以运行(因为粗略计数有 >= 15 个 reviewables),但百分位数聚合没有符合条件的行(因为没有满足 HAVING 的),导致 high0,然后 priority_high 被写入为 0。这会影响 score_to_hide_post 并使其失效。


影响

  • score_to_hide_post 变为 0,这可能错误地导致帖子被视为隐藏或破坏依赖于合理隐藏阈值的逻辑。
  • 这发生在许多 reviewables 但每个只有一个标记/审阅者的情况下,这在小型/中等社区中并不少见。

建议的修复方法(选项)

  1. 在写入之前确保百分位数查询返回足够的行
  • 运行百分位数查询后,检查百分位数是否为 0 以及子查询是否返回了任何行。
  • 如果未返回行,请不要覆盖现有的 priority_high;而是跳过写入,保留先前的值,或回退到配置的默认值。
  • 这是最安全、侵入性最小的方法。
  1. 调整作业触发器以考虑 target_count
  • 修改作业预检查,使其仅在满足 HAVING COUNT(*) >= :target_count 的 reviewables 数量至少为 min_reviewables 时运行。
    换句话说,按 id 分组计算满足 COUNT(*) >= target_count 的 reviewables,并且仅当该计数 ≥ min_reviewables 时才继续。
  1. 允许管理员手动设置 score_to_hide_postpriority_high
  • 在管理员界面中提供一个选项,用于直接输入或调整 score_to_hide_postpriority_high
  • 这样,即使百分位数查询产生意外结果(例如,由于样本太少),系统也可以使用管理员指定的合理阈值,从而防止自动计算导致的错误。