الخلاصة

  • يتيح ifUnchangedBy للعميل أن يربط الكتابة بخصائص محددة، لكنه لا يجوز أن يقيّم خاصية لا يستطيع العميل قراءتها؛ والنتيجة الصحيحة عندئذ هي forbidden لا معلومة نجاح أو فشل.
  • تطابق الشرط يثبت حالة ضيقة عند بدء الطريقة، وatomic:true يثبت وحدة الالتزام داخل Foo/set. لا يثبت أي منهما سلطة الإنسان أو اكتمال الأثر في الأنظمة الأخرى.

كانت الخاصية التي يريدها العميل مضبوطة من الخادم وغير قابلة للتعديل من جانبه. لكنه لم يكن يملك أيضاً حق قراءتها. بدلاً من طلب القيمة مباشرة، وضع تخميناً داخل شرط، ثم انتظر ليرى هل سيقبل الخادم التغيير أم يعيده بسبب عدم التطابق.

إذا أعاد الخادم stateMismatch عند التخمين الخطأ ونجاحاً عند التخمين الصحيح، فلن يكون قد عرض القيمة نصاً، لكنه سيكون قد كشفها سؤالاً بعد سؤال. يصبح الشرط قناة جانبية، ويستطيع المهاجم تضييق الاحتمالات حتى يصل إلى السر.

لذلك يضع JMAP Conditional Set حداً واضحاً: يجب أن يملك العميل صلاحية قراءة كل خاصية يشير إليها الشرط، كما لو أنه طلبها بواسطة Foo/get. إن لم يملكها، فلا يقيّم الخادم التخمين أصلاً، بل يفشل الطلب بـ forbidden.

الوثيقة الحالية هي draft-ietf-jmap-conditional-00 بتاريخ 15 سبتمبر 2026، وتنتهي في 19 مارس 2027. عند تاريخ البحث كانت مسودة إنترنت نشطة في مجموعة JMAP، موجهة إلى Standards Track، وتقترح تحديث RFC 8620 إن اعتُمدت. ليست RFC نهائية، ولا دليلاً على تطبيق منتج أو انتشار تشغيل.

لماذا كانت حراسة النوع كله غير كافية

يوفر JMAP Core الوسيط ifInState. يقارن العميل سلسلة حالة تخص نوعاً كاملاً من الكائنات داخل الحساب. أي تغيير في أي كائن من النوع نفسه قد يبدل السلسلة: وصول رسالة، تعديل من جهاز آخر، أو إجراء بدأه الخادم.

هذه الحراسة تمنع الكتابة على حالة قديمة، لكنها خشنة. قد يُرفض تعديل ملف واحد لأن ملفاً آخر تغير، مع أن الحقيقة التي يعتمد عليها القرار ما زالت صحيحة. كثرة الرفض تدفع بعض التطبيقات إلى إزالة الحراسة أو تكرار الكتابة بلا قراءة، فتستبدل التعارض الظاهر بكتابة عمياء.

يضيف المشروع ifUnchangedBy: خريطة من معرفات الكائنات إلى PatchObjects تصف القيم المتوقعة. يتحقق الشرط عندما يكون تطبيق التصحيح على الكائن الحالي بلا أثر، أي إن كل مؤشر يطابق قيمته. وتدل null على غياب الخاصية. تستخدم المقارنة التمثيل الذي سيعيده Foo/get.

بهذا يستطيع العميل القول: حدّث المحتوى فقط إذا بقي blobId على القيمة القديمة؛ احذف الرسالة فقط إذا بقي $seen غائباً؛ أزل حصة مستخدم فقط إذا كان mayRead ما زال صحيحاً. التغييرات غير المذكورة لا تسبب فشلاً بالضرورة.

هذه الدقة تقلل التعارضات الكاذبة، لكنها تضيق معنى النجاح. لا يقول الرد إن الكائن كله لم يتغير. يقول إن المؤشرات المختارة طابقت القيم المتوقعة في لحظة التقييم عند بدء الطريقة. قد تكون خصائص أخرى قد تغيرت، وقد تكون سياسة المؤسسة نفسها تغيرت خارج نموذج الكائن.

إذا أراد النوع مقارنة الكائن كاملاً، فيمكنه الاعتماد على رمز تغيير يحافظ عليه الخادم ويتبدل عند كل تعديل. لكن قوة هذا الدليل تأتي من انضباط جميع مسارات الكتابة. أداة إدارة أو إصلاح لا تحدث الرمز تجعل ادعاء المقارنة الكاملة غير صحيح مهما بدا الحقل رسمياً.

الرؤية ليست تفويضاً

يسمح المشروع باستخدام خصائص يحددها الخادم ولا يستطيع العميل تعديلها، مثل معرف المحتوى أو الحجم أو وقت التغيير. هذا مفيد لأن القرار يمكن أن يعتمد على واقع لم يصنعه الطالب بنفسه.

لكن حق القراءة شرط سابق. ومن هنا تظهر ثلاثة مستويات يجب ألا تندمج: حق معرفة القيمة، وحق اختبارها كشرط، وحق تنفيذ التغيير. الحق الأول يحد الثاني؛ أما الثالث فيظل قرار تفويض مستقل.

قد يقرأ العميل blobId ويطابقه بدقة ثم يفشل التحديث لعدم امتلاكه إذن الكتابة. وقد يمتلك حساب خدمة إذن الكتابة التقني، من دون أن يملك تفويضاً تنظيمياً لإتلاف الأصل أو تغيير حق طرف آخر. المصادقة تثبت هوية حساب؛ لا تنشئ بالضرورة ولاية على الخسارة.

هذا هو تطبيق عملي لفكرة Heng Lu عن أن الدليل لا يتحول تلقائياً إلى سلطة. طبقة التنسيق الرقيقة يمكن أن تقارن حقائق محددة. لا ينبغي لها أن تتقمص صاحب الأصل أو ممثل المؤسسة أو من يتحمل الأثر.

الشروط تستطيع ربط سياق محدود

تُقيَّم الشروط على حالة الكائنات في بداية الطريقة، قبل تنفيذ أي إنشاء أو تحديث أو حذف داخلها. ويمكن أن يشير الشرط إلى كائن من النوع نفسه لا تعدله الطريقة. قد يشترط تحديث ملف أن يبقى الملف داخل الأب d3 وأن يبقى اسم الأب Reports.

تمنع هذه الصيغة كتابة المحتوى الصحيح في مكان لم يتوقعه العميل بعد نقل متزامن. لكنها لا تثبت كل الأجداد، ولا سياسة الاحتفاظ، ولا القيود القانونية، ولا حالة نظام تخزين خارجي. ما لم يُذكر في الشرط يبقى خارج شهادته.

إذا فشل أي شرط، يجب أن يرفض الخادم الطريقة كلها بـ stateMismatch وألا ينشئ أو يحدث أو يحذف شيئاً. تبقى سلسلة حالة النوع كما هي. ويمكن أن يسمي المعرفات الفاشلة من دون إرجاع قيمها.

من يريد نتائج مستقلة يضع التغييرات في استدعاءات منفصلة. هذا الاختيار يحدد وحدة المصير: الجمع يمنع التقدم الجزئي، والفصل يسمح بحالات وسيطة. التطبيق الذي يعرف تكلفة الضرر هو الذي يجب أن يختار، لا طبقة النقل.

الذرية سؤال مختلف

يضيف المشروع أيضاً atomic:true. في JMAP Core قد تنجح عناصر Foo/set أو تفشل كل على حدة. عند طلب الذرية، يجب أن يلتزم الخادم بكل الإنشاءات والتحديثات والحذف معاً، أو لا يلتزم بأي شيء.

تُفحص القيود على المجموعة النهائية الناتجة عن جميع التغييرات، لا على ترتيب وسيط. لذلك يستطيع كائنان تبديل اسمين فريدين: كل تغيير منفرد يصطدم بالاسم الذي ما زال لدى الآخر، أما النتيجة المشتركة فلا تحتوي تكراراً.

إذا فشل جزء بسبب تصحيح باطل أو تعارض أو إذن أو خطأ آخر، تكون النتيجة atomicFailure ولا يتغير شيء. قد يحدد الخادم العناصر المسببة؛ والعناصر غير المذكورة لم تُنفذ أيضاً، بل لم تكن سبب الفشل.

فشل الشرط يبقى stateMismatch حتى مع طلب الذرية. يحتفظ النظام بذلك بالفرق بين نقطة بداية لم تعد صحيحة ومجموعة تغييرات لا يمكن التزامها كوحدة.

إذا أعلن الخادم القدرة لكنه لا يستطيع تنفيذ طريقة بعينها ذرياً، فعليه أن يعيد cannotApplyAtomically من دون تغيير، ولا يجوز أن يسقط بصمت إلى تطبيق جزئي. يمكن للعميل أن يعيد الطلب من دون atomic فقط إذا قرر أنه يتحمل النتيجة الجزئية.

هذا الطلب الأضعف قرار جديد. يحتاج إلى صاحب صلاحية، ووصف للحالات الوسيطة، وخطة مصالحة. تحويله إلى إعادة محاولة تلقائية يمحو الضمان في اللحظة التي أعلن فيها الخادم أنه لا يستطيع تقديمه.

الالتزام لا يشمل كل العالم

حتى الالتزام الذري الناجح يخص حدود Foo/set في الخادم المجيب. لا تدخل فهارس البحث والإشعارات والذاكرات الوسيطة والنسخ البعيدة والعملاء غير المتصلين تلقائياً في المعاملة نفسها.

قد يتبدل اسمان في قاعدة الكائنات بينما تعرض ذاكرة المسار الربط القديم. وقد تُسحب مشاركة بينما تبقى صلاحية صادرة من نظام آخر فعالة إلى أن تصلها إشارة الإلغاء. وقد تُحذف رسالة ويبقى منها نظير محلي.

السجل الدفاعي يفصل بين: الهوية المصادق عليها، والتفويض المؤسسي، والخصائص التي اختبرها الشرط، واستجابة الطريقة، والقراءة اللاحقة، والجيل الذي رآه كل مستهلك، وأثر المستخدم. تسمية أول رد أخضر «اكتمالاً» تجعل الخادم يشهد عن أنظمة لم يراقبها.

يجب أن تختبر البرمجيات الادعاءات السلبية. غيّر خاصية غير مختارة وتأكد من بقاء الشرط الضيق. غيّر المؤشر المختار وتأكد من عدم حدوث أي تعديل. جرّب خاصية مخفية واطلب forbidden. اجعل عنصراً واحداً في طريقة ذرية يفشل، وافحص ألا يتسرب باقي العمل. ثم أخّر المستهلكين الخارجيين بعد نجاح الالتزام.

رفض تقييم الخاصية المخفية ليس نقصاً في الميزة. إنه حفظ للحد الفاصل بين ما يستطيع العميل معرفته وما يستطيع تخمينه وما يستطيع فعله. وحين يحترم النظام هذه الحدود، تبقى الشروط أدلة دقيقة بدلاً من أبواب سلطة غير معلنة.

المصادر