أشجار تقييم المتطلبات (RET)
نظرة سريعة
ما: الجبر البولياني للأبواب، مع معالجة القيم غير المعروفة (منطق ثلاثي الحالة) لماذا: جعل منطق الأبواب واضحًا، وقابلًا للتدقيق، وحتميًا - لا قواعد مخفية من: المطورون والمشغلون الذين يؤلفون متطلبات أبواب معقدة المتطلبات المسبقة: فهم أساسي للشروط (انظر condition_authoring.md)
لماذا RET؟
المشكلة: كيف يمكنك دمج عدة فحوصات للأدلة في قرار بوابة واحد؟
سيناريو المثال: “أريد نشره في الإنتاج إذا:
- البيئة هي ‘إنتاج’ و
- تم اجتياز الاختبارات وَ
- التغطية تزيد عن 85% و
- تمت الموافقة على الأقل من 2 من 3 مراجعين
بدون RET: سيتعين عليك كتابة كود مخصص لكل بوابة، وهو:
- غير قابل للتدقيق (المنطق مخفي في الكود)
- غير حتمي (يمكن أن يتغير الكود بين التشغيلات)
- من الصعب التحقق منها دون اتصال (لا يمكن إعادة التشغيل دون إعادة تنفيذ الكود)
مع RET: تعبر عن المنطق كهيكل شجري:
{
"requirement": {
"And": [
{ "Condition": "env_is_prod" },
{ "Condition": "tests_ok" },
{ "Condition": "coverage_ok" },
{
"RequireGroup": {
"min": 2,
"reqs": [
{ "Condition": "alice_approved" },
{ "Condition": "bob_approved" },
{ "Condition": "carol_approved" }
]
}
}
]
}
}
الفوائد:
- صريح: المنطق مرئي في مواصفات السيناريو
- قابل للتدقيق: يتم تتبع كل تقييم في حزمة التشغيل
- حتمي: نفس الدليل -> نفس النتيجة
- قابل لإعادة التشغيل: يمكن التحقق منه دون اتصال بالإنترنت دون إعادة استعلام مقدمي الخدمة
[الأمان]: منطق البوابة الصريح يمنع الأبواب الخلفية المخفية. يتم إعلان جميع المنطق في مواصفات السيناريو وتتبعها في حزمة التشغيل للتدقيق.
نموذج ذهني: شجرة تقييم RET
إليك كيفية تقييم شجرة المتطلبات:
RET EVALUATION TREE (simplified)
Gate Requirement (tree structure)
And
|-- Pred(A) -> true
|-- Pred(B) -> unknown
|-- Not(C) -> false
`-- RequireGroup (min: 2)
|-- Pred(D) -> true
|-- Pred(E) -> true
`-- Pred(F) -> false
Strong Kleene Logic: And(true, unknown, true, true) -> unknown
(gate holds)
ترتيب التقييم:
- تقييم شروط الورقة يكون ثلاثي الحالة (صحيح/خطأ/غير معروف)
- تجمع عقد المشغل نتائج الأطفال عبر منطق ثلاثي الحالة
- نتيجة العقدة الجذرية تحدد نتيجة البوابة
نتائج الولايات الثلاث
RET يستخدم منطق ثلاثي الحالة (ليس فقط صحيح/خطأ):
true: تصاريح الدخول (تم استيفاء جميع المتطلبات)false: فشل البوابة (تعارض المتطلبات)unknown: البوابة تحتفظ (المتطلبات غير حاسمة)
لماذا ثلاثي الحالة؟ تغلق البوابات بشكل آمن: تمر البوابة فقط عندما يتم تقييم الشرط إلى true. تمنع النتائج unknown البوابات من المرور حتى اكتمل الدليل.
مثال:
Gate: And(tests_ok, coverage_ok)
Conditions:
- tests_ok: true (tests passed)
- coverage_ok: unknown (coverage report missing)
Outcome: unknown (gate holds until coverage is available)
مشغلات أساسية
و
الدلالات: يجب أن تكون جميع الأطفال true
Truth table (2 operands):
| Left | Right | Result |
|---|---|---|
| true | true | true |
| true | false | false |
| true | unknown | unknown |
| false | (any) | false |
| unknown | true | unknown |
| غير معروف | غير معروف | غير معروف |
مثال:
{
"requirement": {
"And": [
{ "Condition": "tests_ok" },
{ "Condition": "coverage_ok" }
]
}
}
حالة الاستخدام: يجب أن تمر كل من الاختبارات والتغطية
السلوك:
- جميع
true->true(تصاريح البوابة) - أي
false->false(البوابة تفشل) - بخلاف ذلك -> unknown (البوابة مغلقة)
أو
الدلالات: يمكن أن يكون أي طفل true
Truth table (2 operands):
| Left | Right | Result |
|---|---|---|
| true | (any) | true |
| false | false | false |
| false | unknown | unknown |
| unknown | false | unknown |
| غير معروف | غير معروف | غير معروف |
مثال:
{
"requirement": {
"Or": [
{ "Condition": "manual_override" },
{ "Condition": "tests_ok" }
]
}
}
حالة الاستخدام: يجب أن ينجح إما التعديل اليدوي أو الاختبارات الآلية
السلوك:
- أي
true->true(تصاريح البوابة) - جميع
false->false(فشل البوابة) - بخلاف ذلك -> unknown (البوابة مغلقة)
لا
الدلالات: عكس نتيجة الطفل
Truth table:
| Input | Result |
|---|---|
| true | false |
| false | true |
| جدول الحقيقة: | المدخل |
مثال:
{
"requirement": {
"And": [
{ "Condition": "tests_ok" },
{ "Not": { "Condition": "blocklist_hit" } }
]
}
}
حالة الاستخدام: يجب أن تنجح الاختبارات ويجب ألا يتم الوصول إلى القائمة السوداء
السلوك:
صحيح->خاطئخطأ->صحيحunknown->غير معروف(فشل مغلق: لا يمكن تأكيد الغياب)
RequireGroup (نصاب)
الدلالات: يجب أن يكون على الأقل N من M الأطفال true
المعلمات:
min: الحد الأدنى لعدد النتائجtrueالمطلوبةreqs: مصفوفة من المتطلبات الفرعية
مثال:
{
"requirement": {
"RequireGroup": {
"min": 2,
"reqs": [
{ "Condition": "alice_approved" },
{ "Condition": "bob_approved" },
{ "Condition": "carol_approved" }
]
}
}
}
حالة الاستخدام: يجب أن يوافق على الأقل 2 من 3 مراجعين
السلوك:
- عد النتائج
true - إذا كان العدد >=
min->true(تم الوصول إلى النصاب) - إذا كان العدد + غير معروف <
min->false(الحد الأدنى غير ممكن) - بخلاف ذلك -> unknown (في انتظار النصاب)
Truth table examples:
| Outcomes | min | Result | Reason |
|---|---|---|---|
| [true, true, false] | 2 | true | 2 true >= min (quorum reached) |
| [true, unknown, unknown] | 2 | unknown | 1 true, can’t reach min yet |
| [true, false, false] | 2 | false | 1 true, max possible is 1 < min |
| [true, true, unknown] | 2 | true | 2 true >= min (already met) |
| [خطأ، خطأ، خطأ] | 2 | خطأ | 0 صحيح، مستحيل |
[المطور]: راجع ret-logic crate للتنفيذ. يقوم RequireGroup بحساب true/false بشكل مستقل (unknown ليس أي منهما).
شرط (عقدة ورقية)
الدلالات: الإشارة إلى حالة بواسطة المفتاح
مثال:
{
"requirement": { "Condition": "tests_ok" }
}
حالة الاستخدام: بوابة بسيطة بشرط واحد
السلوك:
- يقيم نتيجة الحالة الثلاثية للشرط
- يجب أن توجد الحالة في
ScenarioSpec.conditions
قواعد انتشار ثلاثي الولايات
كيف تنتشر نتائج unknown عبر المشغلين:
و الانتشار
| العمليات | النتيجة | السبب |
|---|---|---|
And(true, true, true) | true | جميع المتطلبات مستوفاة |
And(true, false, true) | false | فشل واحد -> فشل And |
And(true, unknown, true) | unknown | لا يمكن تأكيد جميع القيم صحيحة بعد |
And(false, unknown) | false | فشل واحد (دائرة قصيرة) |
And(unknown, unknown) | unknown | في انتظار الأدلة |
القاعدة: false تهيمن؛ جميع true تعطي true؛ خلاف ذلك unknown
أو انتشار
| العمليات | النتيجة | السبب |
|---|---|---|
Or(false, false, false) | false | جميع المتطلبات فشلت |
Or(true, false, false) | true | واحدة تنجح -> Or تنجح |
Or(false, unknown, false) | unknown | لا يمكن تأكيد جميعها خاطئة بعد |
Or(true, unknown) | true | واحدة تنجح (دائرة قصيرة) |
Or(unknown, unknown) | unknown | بانتظار الأدلة |
القاعدة: true تهيمن؛ جميع false تعطي false؛ خلاف ذلك unknown
توزيع RequireGroup
| النتائج | الحد الأدنى | العدد الحقيقي | العدد المجهول | النتيجة |
|---|---|---|---|---|
| [T, T, F] | 2 | 2 | 0 | صحيح (تم الوصول إلى الحد الأدنى) |
| [T, U, U] | 2 | 1 | 2 | مجهول (الحد الأقصى 3، نحتاج 2) |
| [T, F, F] | 2 | 1 | 0 | خطأ (الحد الأقصى 1 < الحد الأدنى) |
| [U, U, U] | 2 | 0 | 3 | مجهول (الحد الأقصى 3، نحتاج 2) |
| [F, F, F] | 2 | 0 | 0 | خطأ (مستحيل) |
قاعدة:
- إذا كان
true_count >= min->true(تم الوصول إلى النصاب) - إذا كان
true_count + unknown_count < min->false(الحد الأدنى غير ممكن) - بخلاف ذلك -> unknown (في انتظار النصاب)
[LLM Agent]: عندما تعيد RequireGroup
unknown، تحتاج إلى مزيد من الأدلة. تحقق من أي الشروط غير معروفة واعمل على تلبيتها.
حالات الاستخدام العملية
البوابة البسيطة: كلا الشرطين
السيناريو: نشر إذا تم اجتياز الاختبارات و كانت التغطية فوق 85%
{
"gate_id": "quality_gate",
"requirement": {
"And": [
{ "Condition": "tests_ok" },
{ "Condition": "coverage_ok" }
]
}
}
Quorum Gate: 2 من 3 مراجعين
السيناريو: دمج PR إذا تمت الموافقة من قبل 2 على الأقل من 3 مراجعين
{
"gate_id": "review_gate",
"requirement": {
"RequireGroup": {
"min": 2,
"reqs": [
{ "Condition": "alice_approved" },
{ "Condition": "bob_approved" },
{ "Condition": "carol_approved" }
]
}
}
}
بوابة الاستبعاد: غير مدرجة في القائمة السوداء
السيناريو: نشر إذا لم يكن مدرجًا في القائمة السوداء
{
"gate_id": "blocklist_gate",
"requirement": {
"Not": { "Condition": "blocklist_hit" }
}
}
بوابة معقدة: (A و B) أو C
السيناريو: نشر إذا (تم اجتياز الاختبارات و كانت التغطية جيدة) أو تجاوز يدوي
{
"gate_id": "deploy_gate",
"requirement": {
"Or": [
{
"And": [
{ "Condition": "tests_ok" },
{ "Condition": "coverage_ok" }
]
},
{ "Condition": "manual_override" }
]
}
}
تفرع على نتائج البوابة
يمكنك التوجيه إلى مراحل مختلفة بناءً على نتائج البوابة باستخدام advance_to.branch:
{
"advance_to": {
"kind": "branch",
"branches": [
{ "gate_id": "env_gate", "outcome": "true", "next_stage_id": "ship" },
{ "gate_id": "env_gate", "outcome": "unknown", "next_stage_id": "hold" },
{ "gate_id": "env_gate", "outcome": "false", "next_stage_id": "deny" }
],
"default": null
}
}
كيف يعمل:
- تقييم البوابة
env_gate - تحقق من النتيجة مقابل الفروع (من الأعلى إلى الأسفل)
- الفرع المطابق الأول يفوز
- إذا لم يكن هناك تطابق و
defaultفارغ -> خطأ
حالات الاستخدام:
- صحيح: التقدم إلى نشر الإنتاج
- غير معروف: انتظر للمراجعة اليدوية
- خاطئ: رفض وإخطار
[الأمان]: استخدم التفرع لتنفيذ خيارات الطوارئ الآمنة. على سبيل المثال، قم بتوجيه
unknownإلى مراجعة يدوية بدلاً من التقدم التلقائي.
وضع المنطق: كلين القوي
يستخدم Decision Gate منطق Strong Kleene (ثلاثي الحالة):
الخصائص الرئيسية:
And(true, unknown)->unknown(لا يمكن تأكيد أن جميعها صحيحة)Or(false, unknown)->unknown(لا يمكن تأكيد أن جميعها خاطئة)Not(unknown)->unknown(لا يمكن عكس عدم اليقين)
بديل (لم يُستخدم): منطق بوشفار (أي غير معروف -> غير معروف)
لماذا كلاين؟
- أكثر بديهية للأدلة الجزئية
- دوائر قصيرة عند الإمكان (
And(false, unknown)->false) - الفشل في التوازن مع قابلية الاستخدام
[المطور]: راجع crates/ret-logic/src/lib.rs لخوارزمية التقييم.
حالات الاستخدام
أساسي: بوابات معقدة تتطلب تركيبات بوليانية (و، أو، نصاب) ثانوي: بوابات بسيطة مع شروط فردية (عقدة الشرط فقط) نموذج مضاد: لا تقم بتعشيش RETs بعمق شديد - يفضل الشروط المركزة والأشجار المسطحة
استكشاف الأخطاء وإصلاحها
المشكلة: البوابة عالقة في unknown
الأعراض: البوابة لا تمر أبداً، دائماً تعود unknown
السبب: واحدة أو أكثر من الشروط تقيم إلى unknown
الحل:
- تحقق من تتبع البوابة لمعرفة أي الشروط هي
unknown - إصلاح مشكلات الحالة الأساسية (انظر condition_authoring.md)
- Common causes:
- خطأ في المزود (على سبيل المثال، الملف مفقود لمزود json)
- لم يتم العثور على JSONPath (عدم تطابق مخرجات الأداة)
- عدم تطابق النوع لمقارن حساس لنوع البيانات
المشكلة: RequireGroup لا تنجح أبداً
الأعراض: RequireGroup دائمًا ما تعيد false أو unknown
السبب: min مرتفع جدًا، أو عدد كبير من الشروط فشل.
الحل:
- تحقق من قيمة
minمقابل عدد الشروط - تحقق من نتائج الحالة في تتبع البوابة
- تأكد من أن هناك على الأقل
minشرط يمكن أن يكونtrueفي نفس الوقت
مثال:
// BAD: min is 3, but only 2 conditions
{
"RequireGroup": {
"min": 3,
"reqs": [
{ "Condition": "a" },
{ "Condition": "b" }
]
}
}
// GOOD: min <= number of conditions
{
"RequireGroup": {
"min": 2,
"reqs": [
{ "Condition": "a" },
{ "Condition": "b" },
{ "Condition": "c" }
]
}
}
مشكلة: الفرع لا يتطابق
الأعراض: خطأ في تقييم البوابة: “لا يوجد فرع مطابق”
السبب: نتيجة البوابة لا تتطابق مع أي فرع، و default هو null
الحل:
- أضف فروعًا لجميع النتائج الممكنة (صحيح/خطأ/غير معروف)
- أو تعيين
defaultإلى مرحلة احتياطية - مثال:
{
"branches": [
{ "gate_id": "gate1", "outcome": "true", "next_stage_id": "ship" },
{ "gate_id": "gate1", "outcome": "false", "next_stage_id": "deny" }
],
"default": "hold" // Fallback for unknown
}
نصائح التأليف
1. حافظ على استقرار مفاتيح الحالة ووصفها بدقة
- استخدم
tests_okوليسpred1 - يتم الإشارة إلى المفاتيح في حزم التشغيل للتدقيق
2. استخدم RequireGroup لفحوصات نمط النصاب
- مثال: “2 من 3 مراجعين”، “3 من 5 فحوصات مركز البيانات”
- بديل: شروط متعددة و (لكن أقل مرونة)
3. تفضيل الأشجار الصغيرة ذات الظروف المركزة
- أسهل في التدقيق والفهم
- أسهل في تصحيح الأخطاء عند فشل البوابات
4. تحقق من هيكل RET أثناء تعريف السيناريو
- بوابة القرار تتحقق من RETs في وقت
scenario_define - يفشل بسرعة إذا كانت البنية غير صالحة (على سبيل المثال، الإشارة إلى شروط غير موجودة)
5. استخدم التفرع كوسيلة احتياطية آمنة
- توجيه
unknownللمراجعة اليدوية - Route
falseto alert/deny - Route
trueto advance
مسارات التعلم المتقاطعة
مسار المستخدم الجديد: getting_started.md -> condition_authoring.md -> هذا الدليل -> integration_patterns.md
مسار المنطق المتقدم: هذا الدليل -> evidence_flow_and_execution_model.md -> فهم كيف تتناسب RETs مع خط تقييم الأداء
مسار الأمان: هذا الدليل -> security_guide.md -> تعلم كيف تمنع المنطق الصريح الأبواب الخلفية
معجم
و: مشغل يتطلب أن تكون جميع الأطفال true.
البوابة: نقطة قرار في سيناريو، يتم تقييمها عبر RET مقابل الأدلة.
أو: عامل يتطلب أن يكون أي طفل true.
ملاحظة: المشغل يعكس نتيجة الطفل (true <-> false).
الحالة: تعريف فحص الأدلة: استعلام + مقارن + قيمة متوقعة.
RequireGroup: مشغل النصاب يتطلب أن يكون على الأقل N من M الأطفال true.
RET: شجرة تقييم المتطلبات، الجبر البولياني (و/أو/ليس/RequireGroup) للأبواب.
TriState: نتيجة التقييم: true (نجاح)، false (فشل)، أو unknown (معلق).
منطق كلين القوي: وضع منطق ثلاثي الحالات حيث And(true, unknown) -> unknown.