المقترح RFC-0013: مساهمات الوصفات من المجتمع
الحالة: مقترح، 2026-10-06. النوع: إضفاء طابع رسمي على ملف تعريف مسودة؛ تعريف إضافي واحد في catalog.schema.json؛ أداتان جديدتان؛ تكامل مستمر (CI) جديد؛ مسارات واجهة برمجية جديدة. متعلق بالسلامة: بشكل غير مباشر (الوصفة السيئة تكون عند المستوى V0 بالقاعدة وتمر عبر دورة الحياة الحالية، ولا تُنفَّذ أبدًا).
المشكلة #
يمكن لأي شخص الاستعلام عن Cookwala واستخدامه، لكن الوصفات نفسها جاءت من مصدر واحد (fifi.cooking، المقترح RFC-0009) عبر خط أنابيب واحد يتحكم فيه المؤسس. لا توجد طريقة لشخص خارج ذلك الخط لإضافة وصفة: لا نطاق مسمّى (namespace) يُطالَب به، ولا قائمة تحقق، ولا مسار CI، ولا واجهة برمجية. "فهرس وصفات مفتوح" يحتاج إلى باب للدخول، لا باب للخروج فقط، وباب لا يسمح لمساهم بأن يتعارض مع معرّفات مساهم آخر، أو يدّعي حقوقًا لا يملكها، أو يحصل على وصفة موسومة بتحقق أعلى مما هي عليه فعلًا.
الاقتراح #
- **
recipes/community/** تحوي كل وصفة مقدَّمة من المجتمع، في مجلد فرعي واحد لكل بادئة معرّف مُطالَب بها:recipes/community/<prefix>/<id>.cookwala.json، ويبدأidبـ<prefix>-. مجموعات المؤسس الخاصة (archive، وchefteta، وosool، وabdennour، وabuhaty، وworld) تبقى دون مساس، وتصبح بادئاتها محجوزة. - **
recipes/community/NAMESPACES.json** يسجّل مُدخلًا واحدًا لكل بادئة مُطالَب بها:prefix، وowner(اسم مستخدم GitHub الذي أثبت الملكية بفتح طلب الدمج المُطالِب)، وطريقةverification، وaddedAt. تُطالَب البادئة مرة واحدة، في طلب الدمج نفسه الذي يحمل أول وصفة تحتها، ولا يُعاد استخدامها أبدًا حتى لو سُحبت كل وصفة تحتها لاحقًا. تعريف$defإضافي جديد باسمCommunityNamespaceFileفيcatalog.schema.jsonلهذا الملف. - ثلاثة أبواب، مدقّق واحد. طلب الدمج، وأداة سطر الأوامر، وواجهة البرمجة (أدناه) تنتج جميعها الملف نفسه في المكان نفسه ويُفحَص بالكود نفسه، فتكون الإجابة واحدة في كل مكان:
- **
tools/check_community_namespaces.py**: معرّف كل وصفة يطابق بادئة مُطالَب بها وغير محجوزة؛ وتعيش الوصفة تحت المجلد المسمّى باسم بادئتها؛ ومع--author <login>، تكون البادئة مملوكة لذلك الحساب (يُستخدم في طلبات الدمج). - مدمجة في
tools/validate_specs.py، فيحصلrecipes/community/على الفحوص نفسها للمخطط (schema) والدلالات (semantics) التي يحصل عليها كل شيء آخر فيrecipes/، دون أمر منفصل يجب تذكّره. .github/workflows/community-recipes.ymlيشغّل الفحصين معًا عند كل طلب دمج يلمسrecipes/community/**ويعلّق بالنتيجة.
- **
- مستوى التقديم هو V0 دائمًا (المقترح RFC-0009): الوصفة المُقدَّمة توصَف، ولا تكون قابلة للتنفيذ، حتى تمر بالمسار نفسه الذي تمر به أي وصفة للوصول إلى V1. وهذا يعني أيضًا أنها لا تحتاج إلى خبرة في الرسم البياني للعمليات لتقديمها.
- الحقوق، بالقاعدة نفسها لكل مجموعة أخرى. يمكن أن تكون وصفة المساهم الخاصة
CC-BY-4.0أوCC0. والوصفة المنسوبة لشخص آخر تدخل كـLicenseRef-source-credited، حقائق فقط، دون نص خطوات، تمامًا مثلchefteta، وosool، وabdennour، وabuhaty، وworldاليوم (tools/export_fifi.collections.json). - طلب دمج على GitHub (
.github/PULL_REQUEST_TEMPLATE/recipe-submission.md) هو الباب الأساسي لمن يملك git: أضف الملف، وطالِب بالبادئة إن احتجت، ووقّع (اتفاقية ترخيص المساهم الحالية)، وافتح طلب الدمج. تُشغَّل الفحوص أعلاه تلقائيًا؛ ويراجع أحد القائمين على المشروع أول تقديم تحت كل بادئة جديدة، وبعد ذلك قد يُدمَج التقديم الذي يجتاز الفحوص تلقائيًا (قرار تشغيلي، لا يُحدَّد في هذا المقترح). - نموذج issue على GitHub (
.github/ISSUE_TEMPLATE/recipe-submission.yml) هو الباب لمن لا يملك git: اسم الطبق، والمكونات، والخطوات، وعدد الحصص، والحقوق. لا يملك الـ issue وصولًا إلى هذا المستودع، لذا تحوّلهtools/recipe_from_issue.pyإلى الملف نفسه بالضبط (تحليل نص حر بأفضل جهد ممكن، البديل الاحتياطي الموثّق نفسه الذي يستخدمه استيراد fifi.cooking: الكميات غير المحلَّلة تصبح قطعة واحدة مع الاحتفاظ بالنص الأصلي) ويفتح.github/workflows/recipe-issue-to-pr.ymlطلب دمج مسودة منه تلقائيًا، في نطاق الاستقبال المشتركissue-، مُعلَّمًا لمراجعة بشرية. - واجهة برمجية (مسارات جديدة في
api/index.openapi.yaml): يقبلPOST /v1/recipes/submissionsوثيقة Cookwala (ولاحقًا، وثيقةRecipeبصيغة schema.org)، وينفّذ الفحوص نفسها التي ينفذهاtools/validate_specs.pyوtools/check_community_namespaces.py، ويفتح طلب دمج عبر تطبيق GitHub — على غرار المسار الحاليPOST /v1/registry/submissions("يُراجَع، ويمكن أيضًا عبر طلب دمج على GitHub"). التوثيق يكون برمز GitHub (بادئة المُقدِّم نفسه) أو برمز نشر مرتبط بنطاق تم التحقق منه (طرق الإثبات في المقترح RFC-0002). يُبلغGET /v1/recipes/submissions/{id}عن حالة CI وطلب الدمج الناتج أو الدمج نفسه. هذه الخدمة ليست شرطًا لعمل البابين الأول والثاني أعلاه؛ فهي إضافية. - لا توجد أداة كتابة في MCP. يمكن للوكلاء (agents) تشغيل المدقّق والحصول على قائمة مشكلات منظَّمة؛ ولا شيء في
sdk/mcp-jsيفتح طلب دمج أو يستدعي مسار التقديم. نص الوصفة الذي يصل إلى وكيل هو بيانات (AGENTS.mdفيcookwala/)، وليس تعليمات أبدًا، ولا تُنشر الوصفة لأن وكيلًا قرر أنها ينبغي أن تُنشر. - الاتحاد اللامركزي (federation) يبقى مسار التوسّع الحقيقي. الناشر الذي يريد الاحتفاظ بوصفاته على موقعه الخاص لا يستخدم خط الأنابيب هذا على الإطلاق: يسجّل
recipe_collectionفي السجل (المقترح RFC-0002) مع hash، ويُدرجه الدليل. التقديم إلى هذا المستودع هو لمن ليس لديه فهرس خاص به.
بدائل جرى النظر فيها #
- قاعدة بيانات ونظام حسابات. مرفوض: يكرر ما يوفره مستودع GitHub بالفعل (الهوية، والمراجعة، والتاريخ، وCI)، ولا يُشغّل هذا المشروع أي خادم اليوم.
- **وصول كتابة مفتوح إلى
recipes/دون نطاق مسمّى.** مرفوض: تعارض المعرّفات وانتحال وصفات مساهم آخر، السبب نفسه الذي يجعل السجل (registry) يثبت النطاقات المسمّاة (المقترح RFC-0002). - اشتراط أن يدخل كل تقديم عند مستوى التحقق الذي يدّعيه. مرفوض: لا يستطيع أحد خارج عملية المراجعة الخاصة بالمؤسس اليوم إنتاج أدلة V1 لوصفة جديدة؛ والدخول عند V0 فقط يبقي الأمر صادقًا ويُبقي سقف التقديم منخفضًا.
الانتقال #
إضافي بالكامل. لا يتغير معنى أي وصفة، أو مخطط، أو مسار واجهة برمجية موجود.
أسئلة مفتوحة #
- سياسة الدمج التلقائي بعد أول تقديم مُراجَع تحت بادئة: يحدد هذا المقترح الفحوص، لا ما إذا كان اجتياز نظيف يُدمَج دون إشراف. تشغيلي، يُسجَّل في
docs/DECISIONS.mdبمجرد اتخاذ القرار. - هل تُشغَّل واجهة التقديم البرمجية كـ Cloudflare Worker، أو كإجراء GitHub Action يُستدعى عبر
repository_dispatch، أو بطريقة أخرى: تفصيل تنفيذي، لا معياري. - حد لمعدل الطلبات لكل مُقدِّم ومعالجة إساءة الاستخدام في الواجهة البرمجية، على غرار السؤال المفتوح الثاني في المقترح RFC-0002 الخاص بالسجل.