"مراجعة عطل مسار النشر عبر متصفح OpenClaw: من fields are required إلى إصلاح على مستوى النظام لـ stale ref"

مراجعة عطل مسار النشر عبر متصفح OpenClaw: من fields are required إلى stale ref وإصلاح على مستوى النظام

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

الفئة المستهدفة:

  • من يستخدم أداة browser في OpenClaw لأتمتة النشر/تعبئة النماذج
  • من واجه fields are required أو Element \"eXX\" not found or not visible أو No tool call found for function call output ...
  • من يريد ترقية “حل إسعافي مؤقت” إلى “حل إصلاح مستقر وقابل لإعادة الاستخدام”

أولًا: الظاهرة والأثر على العمل

1) الأخطاء الرئيسية

في هذا العطل ظهرت ثلاثة أنواع نموذجية من الأخطاء:

  1. fields are required
  2. Element \"e92\" not found or not visible. Run a new snapshot to see current page elements.
  3. 400 No tool call found for function call output with call_id ...

2) المظهر التشغيلي

  • الصفحة تفتح
  • يمكن أخذ snapshot من DOM
  • عند الوصول إلى act/fill أو إجراء إدخال على عقدة، تتوقف خدمة تحكّم المتصفح بخطأ
  • يؤدي ذلك إلى تعطل تدفق النشر عبر مواقع متعددة (Linux.do / V2EX / 2libra / iSharkFly) وعدم القدرة على تنفيذه بشكل متسلسل

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


ثانيًا: الخط الزمني (النقاط الأساسية)

  • حوالي 2026-02-23 12:44 (CST): تم تثبيت/ترقية OpenClaw على الجهاز إلى 2026.2.22-2
  • بعدها ظهرت بكثرة أخطاء المتصفح: fields are required
  • مع التقدم أكثر ظهرت stale ref: Element \"e92\" not found or not visible
  • في جلسات سابقة كان موجودًا: No tool call found for function call output ...
  • في النهاية تم استعادة النشر بنجاح بعد إصلاح توافق البروتوكول + معالجة stale ref مع آليات احتياطية

ملاحظة:

  • No tool call found ... و fields are required ليستا نفس المشكلة.
  • تقليل نافذة السياق (مثل 1048576 → 200000) لا يصلح هذين الخطأين الجذريين مباشرة.

ثالثًا: تفكيك الأسباب الجذرية

السبب الجذري A: عدم توافق بروتوكول fill (أول ما انفجر)

الشكل الشائع لطلب الفعل من المنبع يكون:

{
  "kind": "fill",
  "ref": "e57",
  "text": "..."
}

بينما التنفيذ الحالي للمسار يميل إلى اشتراط:

{
  "kind": "fill",
  "fields": [
    { "ref": "e57", "type": "text", "value": "..." }
  ]
}

عندما لا تُقدَّم fields ولا توجد خريطة توافق، يتم إطلاق fields are required مباشرة.

السبب الجذري B: الصفحات الديناميكية تسبب انزياح ref (stale ref)

مثلًا:

  • عند snapshot يتم الحصول على e92
  • بعد إعادة رسم مكونات الصفحة/تبديل طبقة منبثقة، تصبح e92 غير صالحة
  • تستمر type/fill اللاحقة باستخدام ref القديم فتُطلق not found or not visible

هذا شائع جدًا في واجهات ديناميكية مثل حقل إدخال اختيار العقد (node) في V2EX.

السبب الجذري C: No tool call found ... هو اختلال حالة استدعاء الجلسة

هذا الخطأ ناتج عن عدم اتساق مسار session/tool-call (عدم تطابق call_id)، وليس فشل عمليات DOM للمتصفح بحد ذاتها.


رابعًا: أهداف الإصلاح والاستراتيجية

الهدف ليس “ترقيعًا نقطيًا”، بل تحويل مسار النشر إلى “توافق + تعافٍ ذاتي + قابلية للرصد”:

  1. التوافق مع شكل الطلب القديم لتجنب fields are required
  2. تعافٍ تلقائي من stale ref دون طلب إعادة snapshot يدويًا في كل مرة
  3. وجود آلية احتياطية حتى عند الفشل للمرة الثانية كي لا ينهار التدفق عند نقاط الكتابة الحرجة

خامسًا: التغييرات الفعلية (dist وقت التشغيل)

ملاحظة: بعد حزم OpenClaw توجد عدة مخرجات hash، ويجب استكمال الفروع الحرجة كلها بالتزامن لتجنب أن يصيب التشغيل bundle غير المُصلَّح.

1) طبقة توافق fill

ضمن case "fill" في /act تمت إضافة خريطة توافق:

  • عند غياب fields يتم تحويل {ref,text/value} تلقائيًا إلى fields:[{ref,type:"text",value}]
  • وتوفير قيمة افتراضية لـ type وهي text

2) إعادة المحاولة التلقائية لـ stale ref

ضمن case "type" و case "fill":

  • التقاط Unknown ref / not found or not visible
  • تنفيذ snapshotRoleViaPlaywright({ refsMode: "aria" }) مرة واحدة تلقائيًا
  • ثم إعادة تنفيذ الفعل الأصلي

3) طبقة احتياطية ثانية (تعزيز محوري هذه المرة)

إذا فشل “إعادة snapshot + إعادة المحاولة” بسبب stale ref أيضًا:

  • بالنسبة لـ type: محاولة الكتابة مباشرة إلى document.activeElement مع إطلاق input/change
  • بالنسبة لـ fill: في سيناريو نص أحادي الحقل، يتم اتباع نفس احتياطية activeElement

هذا يغطي السيناريو الشائع “التركيز ما زال على حقل الإدخال الهدف، لكن ref القديم لم يعد صالحًا”.

4) الملفات المعنية

  • /opt/homebrew/lib/node_modules/openclaw/dist/routes-CmNAokG-.js
  • /opt/homebrew/lib/node_modules/openclaw/dist/routes-FGJF5gtZ.js
  • /opt/homebrew/lib/node_modules/openclaw/dist/pi-embedded-helpers-CNhhELVT.js
  • /opt/homebrew/lib/node_modules/openclaw/dist/pi-embedded-helpers-DxTyisc4.js

سادسًا: خطوات التحقق (قابلة لإعادة الإنتاج)

  1. إعادة تشغيل gateway والتأكد من سريان العملية الجديدة (تغيّر PID)
  2. تشغيل نفس مسار النشر الآلي
  3. مراقبة السجلات هل ما زالت تظهر:
    • fields are required
    • Element \"eXX\" not found or not visible
  4. التحقق من نتيجة العمل: هل تم إنشاء المنشور فعليًا بنجاح

نتيجة هذه المرة:

  • تم استعادة المسار المتعطل ونجح النشر.

سابعًا: لماذا “كان طبيعيًا قبل يومين، وهذه المرة نحتاج كل هذا التغيير”؟

الخلاصة واضحة:

  1. تغيّر الإصدار ضخم الفروقات البروتوكولية

    • الإصدار الحالي على الجهاز: [email protected]
    • في هذا الإصدار أصبح مدخل fill أكثر صرامة تجاه شكل fields[]
  2. نفس المشكلة يجب استكمالها في عدة مداخل dist

    • يبدو وكأنه “تعديل ملفات كثيرة”، لكنه في الجوهر “نفس المنطق موجود مكررًا عبر عدة مخرجات حزم”
  3. انزياح ref في الصفحات الديناميكية مخاطرة طبيعية

    • عدم الاصطدام بها سابقًا لا يعني عدم وجودها
    • عندما تصبح إعادة الرسم أكثر تكرارًا ستنفجر بشكل جماعي

لذلك هذه المرة ليست “مشكلة إعدادات فقط”، بل فجوة مزدوجة: “توافق البروتوكول + استقرار واجهة UI الديناميكية”.


ثامنًا: توصيات لاحقة (منع الارتداد)

1) توصيات على مستوى البروتوكول

  • توضيح canonical schema لـ fill ضمن بروتوكول browser action
  • الحفاظ على نافذة توافق رجعي مع schema القديم، مع تنبيه في السجلات حول الترحيل

2) توصيات على مستوى التنفيذ

  • إضافة مفتاح قابل للتهيئة لتفعيل snapshot تلقائي مسبقًا قبل type/fill/click (وضع ثبات عالٍ)
  • تسجيل سجلات بنيوية (structured logs) لفرع إعادة المحاولة لـ stale-ref (لتأكيد ما إذا تم تفعيل الاحتياطية)

3) توصيات تشغيلية (Ops)

  • بعد كل ترقية شغّل حدًا أدنى من E2E: open → snapshot → fill → submit
  • ربط الأخطاء الحرجة (fields are required، Unknown ref) بنظام إنذار

4) توصيات على مستوى الجلسة

  • تتبع No tool call found ... بشكل مستقل (سلامة الجلسة/اتساق إعادة التشغيل)، ولا تخلطه مع مشاكل DOM للمتصفح

تاسعًا: قائمة استكشاف الأعطال (لنفسك في المستقبل)

عند مواجهة مشاكل مشابهة، اتبع هذا التسلسل:

  1. افصل نوع الخطأ أولًا (بروتوكول/DOM/session)
  2. راجع أحدث نقطة زمنية في السجل، لتجنب إساءة التشخيص بناءً على خطأ قديم
  3. تحقق أن شكل payload للطلب يطابق الإصدار الحالي
  4. أضف لـ stale ref: “إعادة محاولة بعد snapshot + احتياطية activeElement”
  5. أعد التشغيل وتأكد أن العملية الجديدة حمّلت الشيفرة الجديدة
  6. أعد الاختبار على نفس المسار وتأكد من نجاح العمل، لا مجرد اختفاء الخطأ

عاشرًا: الخاتمة

إصلاح هذه المرة ليس “إخفاء الخطأ”، بل استكمال مسار النشر ليملك ثلاث طبقات من المرونة:

  • الطبقة الأولى: توافق البروتوكول (منع عدم تطابق البنية)
  • الطبقة الثانية: تعافٍ تلقائي (إعادة المحاولة بعد snapshot)
  • الطبقة الثالثة: احتياطية الإدخال (الكتابة عبر activeElement)

الهدف النهائي واحد: جعل الأتمتة على صفحات ويب ديناميكية حقيقية قابلة للاستمرار، وقابلة لإعادة الإنتاج، وقابلة للصيانة.

إذا كنت تعمل أيضًا على أتمتة متصفح OpenClaw، يُنصح بتثبيت هذه الاستراتيجية ذات الطبقات الثلاث كقالب افتراضي مباشرة.