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). إذا كان معظم العناصر القابلة للمراجعة لديها علم واحد فقط، فإن الاستعلام الفرعي للنسبة المئوية لا يُرجع شيئًا → 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_reviewables هو 15.

  • تحسب المهمة high باستخدام 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

مع :target_count عادة ما يكون 2.


السبب الجذري

هناك عتبتان منفصلتان تخلقان فجوة معًا:

  1. يتم تشغيل المهمة عندما يكون هناك ما لا يقل عن min_reviewables (15) عنصر قابل للمراجعة فوق min_priority_threshold - هذا عدد تقريبي يتجاهل متطلب :target_count.
  2. ولكن حساب النسبة المئوية الذي ينتج high يشمل فقط العناصر القابلة للمراجعة التي لديها COUNT(*) >= :target_count (أي، ما لا يقل عن 2 من reviewable_scores). إذا كان لدى العديد من العناصر القابلة للمراجعة علامة واحدة فقط، فإن الاستعلام الفرعي لا يُرجع أي صفوف وتُرجع النسبة المئوية القيمة الافتراضية 0.0.

لذلك يمكن تشغيل المهمة (لأن هناك >= 15 عنصرًا قابلاً للمراجعة حسب العدد التقريبي) ولكن تجميع النسبة المئوية لا يحتوي على صفوف مؤهلة (لأن لا شيء يلبي HAVING)، مما يتسبب في أن يكون high هو 0 ثم يتم كتابة priority_high كـ 0. يتغذى ذلك على score_to_hide_post ويؤدي إلى انهياره.


التأثير

  • يصبح score_to_hide_post هو 0، مما قد يتسبب بشكل غير صحيح في اعتبار المشاركات مخفية أو كسر المنطق الذي يعتمد على عتبة إخفاء معقولة.
  • يحدث هذا في المواقع التي توجد بها العديد من العناصر القابلة للمراجعة ولكن كل منها يحتوي على علامة/مُراجع واحدة فقط، وهو أمر شائع في المجتمعات الصغيرة/المتوسطة.

الإصلاحات المقترحة (خيارات)

  1. ضمان أن استعلام النسبة المئوية يُرجع عددًا كافيًا من الصفوف قبل الكتابة
  • بعد تشغيل استعلام النسبة المئوية، تحقق مما إذا كانت قيمة النسبة المئوية هي 0 وما إذا كان الاستعلام الفرعي قد أعاد أي صفوف.
    إذا لم يتم إرجاع أي صفوف، لا تقم بالكتابة فوق priority_high الحالي؛ بدلاً من ذلك، تخطى الكتابة، احتفظ بالقيمة السابقة، أو ارجع إلى قيمة افتراضية تم تكوينها.
  • هذا هو النهج الأكثر أمانًا والأقل تدخلاً.
  1. تعديل مشغل المهمة لحساب target_count
  • قم بتعديل الفحص المسبق للمهمة بحيث تعمل فقط عندما يكون عدد العناصر القابلة للمراجعة التي تلبي HAVING COUNT(*) >= :target_count على الأقل min_reviewables.
    بمعنى آخر، قم بعد العناصر القابلة للمراجعة مجمعة حسب id التي تلبي COUNT(*) >= target_count وتابع فقط إذا كان هذا العدد >= min_reviewables.
  1. السماح للمسؤولين بتعيين score_to_hide_post أو priority_high يدويًا
  • قم بتوفير خيار في واجهة المسؤول لإدخال أو تعديل score_to_hide_post أو priority_high مباشرة.
  • بهذه الطريقة، حتى لو أنتج استعلام النسبة المئوية نتائج غير متوقعة (على سبيل المثال، بسبب قلة العينات)، يمكن للنظام استخدام عتبة معقولة يحددها المسؤول، مما يمنع الأخطاء الناتجة عن الحسابات التلقائية.