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 0 → score_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
highusando 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:
- O job é acionado quando há pelo menos
min_reviewables(15) reviewables acima demin_priority_threshold— esta é uma contagem grosseira que ignora o requisito de:target_count. - Mas o cálculo do percentil que produz
highinclui apenas reviewables que atendem aCOUNT(*) >= :target_count(ou seja, pelo menos2reviewable_scores). Se muitos reviewables tiverem apenas uma flag, a subquery não retorna nenhuma linha e o percentil retorna o valor padrão0.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_postse torna0, 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)
- 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 é
0e se a subquery retornou alguma linha.
Se nenhuma linha foi retornada, não sobrescreva opriority_highexistente; 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.
- 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_countfor de pelo menosmin_reviewables.
Em outras palavras, conte os reviewables agrupados poridque satisfazemCOUNT(*) >= target_counte só prossiga se essa contagem for ≥min_reviewables.
- Permitir que administradores definam manualmente
score_to_hide_postoupriority_high
- Forneça uma opção na interface de administração para inserir ou ajustar diretamente
score_to_hide_postoupriority_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.