Score_to_hide_post se torna 0 quando os revisáveis têm apenas uma bandeira

Resumo

score_to_hide_post pode ser levado a 0 porque o job em background Jobs::ReviewablePriorities escreve priority_#{priorities[:high]} como 0 quando a query de percentil não retorna linhas. O job é acionado quando reviewable_count >= 15, mas o cálculo do percentil inclui apenas reviewables que atendem a HAVING COUNT(*) >= :target_count (onde target_count é tipicamente 2). Se a maioria dos reviewables tiver apenas uma flag, a subquery de percentil não retorna nada → high se torna 0score_to_hide_post = ((high * ratio) * scale).truncate(2) é avaliado como 0. Isso faz com que o limite de ocultação colapse para zero e produza um comportamento de ocultação incorreto.


Origem (código/fatos relevantes)

  • score_to_hide_post é computado via:
score_to_hide_post = ((high.to_f * ratio) * scale).truncate(2)
  • high é lido da plugin store:
PluginStore.get("reviewables", "priority_#{priorities[:high]}")
  • Essa entrada da plugin store é escrita por Jobs::ReviewablePriorities (o job do sistema).
    O job roda quando:
reviewable_count = Reviewable.approved.where("score > ?", min_priority_threshold).count
return if reviewable_count < self.class.min_reviewables

onde self.class.min_reviewables é 15.

  • O job computa high usando SQL:
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

com :target_count geralmente sendo 2.


Causa raiz

Existem dois limites separados que juntos criam uma lacuna:

  1. O job é acionado quando há pelo menos min_reviewables (15) reviewables acima de min_priority_threshold — esta é uma contagem grosseira que ignora o requisito de :target_count.
  2. Mas o cálculo do percentil que produz high inclui apenas reviewables que atendem a COUNT(*) >= :target_count (ou seja, pelo menos 2 reviewable_scores). Se muitos reviewables tiverem apenas uma flag, a subquery não retorna nenhuma linha e o percentil retorna o valor padrão 0.0.

Portanto, o job pode rodar (porque há ≥ 15 reviewables pela contagem grosseira), mas a agregação de percentil não tem linhas qualificadas (porque nenhuma atende ao HAVING), fazendo com que high seja 0 e, em seguida, priority_high seja escrito como 0. Isso alimenta score_to_hide_post e o colapsa.


Impacto

  • score_to_hide_post se torna 0, o que pode incorretamente fazer com que posts sejam considerados ocultos ou quebrar a lógica que depende de um limite razoável de ocultação.
  • Isso ocorre em sites onde existem muitos reviewables, mas cada um tem apenas uma flag/revisor, o que não é incomum em comunidades pequenas/médias.

Correções sugeridas (opções)

  1. Garantir que a query de percentil retorne linhas suficientes antes de escrever
  • Após executar a query de percentil, verifique se o valor do percentil é 0 e se a subquery retornou alguma linha.
    Se nenhuma linha foi retornada, não sobrescreva o priority_high existente; em vez disso, pule a escrita, mantenha o valor anterior ou use um padrão configurado como fallback.
  • Esta é a abordagem mais segura e menos invasiva.
  1. Ajustar o gatilho do job para considerar target_count
  • Modifique a pré-verificação do job para que ele só rode quando o número de reviewables que atendem a HAVING COUNT(*) >= :target_count for de pelo menos min_reviewables.
    Em outras palavras, conte os reviewables agrupados por id que satisfazem COUNT(*) >= target_count e só prossiga se essa contagem for ≥ min_reviewables.
  1. Permitir que administradores definam manualmente score_to_hide_post ou priority_high
  • Forneça uma opção na interface de administração para inserir ou ajustar diretamente score_to_hide_post ou priority_high.
  • Dessa forma, mesmo que a query de percentil produza resultados inesperados (por exemplo, devido a poucas amostras), o sistema pode usar um limite razoável especificado pelo administrador, evitando erros causados por cálculos automáticos.