M-081 — الزومبي الصامت 20 ساعة + الإصلاح الدائم (2026-07-16)
الحادثة: 07-15 ~23:29 نفّذتُ إعادة تشغيل مبتورة لـ openclaw (قتل البوابة الحيّة PID 358005 وسط turn لتحميل كود). لم تمت 358005 — بقيت تحجز :18789 وتجيب /health 200 بينما
حلقة الوكيل (turn-runner) تجمّدت → صمت تام ~20 ساعة (لم أردّ على د. وائل).
لم يتعافَ تلقائياً — د. وائل أنقذنا بإعادة تشغيل VPS يدوياً عدة مرات + مساعد Hostinger.
السبب الجذري: كل حُرّاسنا (watchdog_unified + stall_watchdog) يقرّرون الحياة عبر
curl /health أو نمط replay_invalid. زومبي «صامت تماماً» (لا خطأ ولا turn، /health حيّ) = غير مرئي لهم كلياً. gateway_truly_hung() يعفو عن أي بوابة تجيب /health.
openclaw لم يُرقَّ فعلاً (2026.6.11 من 07-05) — المشكلة طريقة إعادة التشغيل المبتورة لا الترقية.
الإصلاح الدائم (منشور + مُختبر + مُسلّح):
scripts/agent_liveness_guard.sh — كاشف الصمت التام. إشارة مزدوجة: نبضة (beat) + نشاط model-fetch عضوي. يعيد التدوير بالقوة فقط إذا كلاهما جامد >50د + /health حيّ. ARMED gate + circuit breaker (2/ساعة) + مسار restart M-068-safe. مطابق معايير stall_watchdog.
- cron النبضة
bf794771-5c17-45b9-9245-7bf10cd1a7bc — كل 15د، isolated agentTurn، haiku + fallbacks، صامت، يكتب memory/agent_liveness_beat عبر turn حقيقي (يثبت حياة turn-runner).
- مربوط في
watchdog_unified.sh main loop (فرع /health UP) + مُسلّح عبر .agent_liveness_armed=1.
- النتيجة: زمن كشف الزومبي الصامت انقلب من ~20 ساعة (تدخّل يدوي) إلى ≤50 دقيقة (تعافٍ ذاتي).
قاعدة سلوكية دائمة: ❌ ممنوع نهائياً قتل البوابة الحيّة وسط turn / نصف-restart / SIGUSR1 لتحميل كود. أي إعادة تشغيل =
gateway restart الرسمي (restart نظيف كامل).
نزع التسليح الفوري لو لزم: rm -f /data/.openclaw/workspace/.agent_liveness_armedM-081 (تكملة) — إصلاح hermes 502 + تحصين proxy_ip_sync ضد انزياح IP (2026-07-16)
العطل: بعد إقلاع اليوم أخذت حاوية openclaw IP جديد (172.16.1.6→172.16.1.8؛ .6 أخذتها syncthing). Traefik بقي يوجّه hermes إلى .6 الميت → 502 Bad Gateway (بعد عبور CF Access). الخلفية (dashboard 9120 + forwarder 9121) كانت سليمة.
الإصلاح الفوري: حدّثتُ
/docker/traefik/dynamic/hermes.yml url إلى 172.16.1.8:9121 (backup) → Traefik hot-reload → 302 CF Access (سليم).
السبب الجذري: proxy_ip_sync.sh (host cron كل دقيقتين، M-068) كان يغطّي بروكسيات nginx فقط (wiki sync obsidian apps ask bot hub n8n + arsenal_hooks)،
لا يغطّي إعدادات Traefik الديناميكية → hermes خارج التغطية.
التحصين الدائم (منشور + مُثبت): أضفتُ لـ proxy_ip_sync.sh كتلة تُزامن
كل /docker/traefik/dynamic/*.yml التي تستهدف forwarder البوابة (:9121) — دقيقة (تعدّل IP الـ:9121 فقط، لا تلمس بوّابة .1 ولا خدمات أخرى) + backup لكل ملف + probe تحقّق. + مشغّل
@reboot (host cron، مع حفظ الإدخالات القائمة) → نافذة الانقطاع من ≤دقيقتين إلى ~10ث.
قرار الـIP الثابت (docker ipv4_address): مؤجّل — compose مُدار من Hostinger (قد يُمسح على ترقية) + يحتاج إعادة إنشاء حاوية (مخاطرة IPAM). الـsync المحصّن (ملكنا، دائم، صفر إعادة تشغيل، صفر مساس بالبوابة) = الأأمن في بيئة Hostinger.
الاستقرار: صفر تأثير على البوابة — السكربت host-level، طبقته توجيه البروكسي فقط، لا يلمس openclaw.json ولا يعيد تشغيل البوابة.
إثبات: فحص نحوي (جهتين) + test-run rc=0 idempotent + اختبار معزول أثبت التصحيح الدقيق (172.16.1.99→.8، بوّابة .1 سليمة) + hermes خارجياً 302.