ملخص
يمكن دفع score_to_hide_post إلى 0 لأن المهمة الخلفية Jobs::ReviewablePriorities تكتب priority_#{priorities[:high]} كـ 0 عندما لا تُرجع استعلام النسبة المئوية أي صفوف. يتم تشغيل المهمة عندما reviewable_count >= 15، ولكن حساب النسبة المئوية يشمل فقط العناصر القابلة للمراجعة التي تلبي HAVING COUNT(*) >= :target_count (حيث target_count عادة ما يكون 2). إذا كان معظم العناصر القابلة للمراجعة لديها علم واحد فقط، فإن الاستعلام الفرعي للنسبة المئوية لا يُرجع شيئًا → high يصبح 0 → score_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.
السبب الجذري
هناك عتبتان منفصلتان تخلقان فجوة معًا:
- يتم تشغيل المهمة عندما يكون هناك ما لا يقل عن
min_reviewables(15) عنصر قابل للمراجعة فوقmin_priority_threshold- هذا عدد تقريبي يتجاهل متطلب:target_count. - ولكن حساب النسبة المئوية الذي ينتج
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، مما قد يتسبب بشكل غير صحيح في اعتبار المشاركات مخفية أو كسر المنطق الذي يعتمد على عتبة إخفاء معقولة. - يحدث هذا في المواقع التي توجد بها العديد من العناصر القابلة للمراجعة ولكن كل منها يحتوي على علامة/مُراجع واحدة فقط، وهو أمر شائع في المجتمعات الصغيرة/المتوسطة.
الإصلاحات المقترحة (خيارات)
- ضمان أن استعلام النسبة المئوية يُرجع عددًا كافيًا من الصفوف قبل الكتابة
- بعد تشغيل استعلام النسبة المئوية، تحقق مما إذا كانت قيمة النسبة المئوية هي
0وما إذا كان الاستعلام الفرعي قد أعاد أي صفوف.
إذا لم يتم إرجاع أي صفوف، لا تقم بالكتابة فوقpriority_highالحالي؛ بدلاً من ذلك، تخطى الكتابة، احتفظ بالقيمة السابقة، أو ارجع إلى قيمة افتراضية تم تكوينها. - هذا هو النهج الأكثر أمانًا والأقل تدخلاً.
- تعديل مشغل المهمة لحساب
target_count
- قم بتعديل الفحص المسبق للمهمة بحيث تعمل فقط عندما يكون عدد العناصر القابلة للمراجعة التي تلبي
HAVING COUNT(*) >= :target_countعلى الأقلmin_reviewables.
بمعنى آخر، قم بعد العناصر القابلة للمراجعة مجمعة حسبidالتي تلبيCOUNT(*) >= target_countوتابع فقط إذا كان هذا العدد >=min_reviewables.
- السماح للمسؤولين بتعيين
score_to_hide_postأوpriority_highيدويًا
- قم بتوفير خيار في واجهة المسؤول لإدخال أو تعديل
score_to_hide_postأوpriority_highمباشرة. - بهذه الطريقة، حتى لو أنتج استعلام النسبة المئوية نتائج غير متوقعة (على سبيل المثال، بسبب قلة العينات)، يمكن للنظام استخدام عتبة معقولة يحددها المسؤول، مما يمنع الأخطاء الناتجة عن الحسابات التلقائية.