---
name: huntbug
description: تحقيق خلل موازٍ بأربعة مسارات تُطلَق معاً (Agent tool، رسالة واحدة، 3-4 استدعاءات): git bisect بـworktree معزولة إلزامية · إعادة إنتاج حيّة دنيا بترتيب التصعيد الموثَّق (curl عبر الوسيط → /gate → متصفّح كملاذ أخير) · سلامة بيانات/تعدد مستأجرين/كاش عميل قديم · بيئة ولغة وoauthScopes. لوحة TaskCreate حيّة تُحدَّث أثناء التحقيق لا في النهاية فقط، يليها توليف يُجريه الوكيل المنسِّق نفسه (بلا وكيل حَكَم خامس). الإصلاح يعيد استخدام حلقة TDD الخاصة بـ/gas-pipeline لإصلاح الأخطاء حرفياً. لا يَنشر بنفسه — ينتهي بتسليم صريح لـ/gas-pipeline أو /deliver لإتمام gate→PR→دمج→نشر.
---

# /huntbug — تحقيق خلل موازٍ بأربعة مسارات إلى سبب جذري مؤكَّد

> يستهلك `/gas-pipeline` (حلقة TDD لإصلاح الأخطاء تحديداً — لا يعيد كتابتها) ويُسلِّم إلى
> `/gas-pipeline` أو `/deliver` بعد تأكيد الإصلاح — لا يكرّر منطق gate→PR→دمج→نشر الموجود
> فيهما. **`/huntbug` نفسه لا ينشر أبداً ولا يدمج أبداً** — نطاقه ينتهي عند "إصلاح مؤكَّد جاهز
> للتسليم".

## 0) استقبال بلاغ الخلل — لوحة `TaskCreate`

عند استلام بلاغ خلل، أنشئ لوحة مهام مشتركة **قبل** إطلاق أي وكيل تحقيق:

**بنية `TaskCreate` (إلزامية — `TaskCreate` مسطّح، لا يدعم أب/تابع فعلياً):**
1. مهمّة تنسيق واحدة (`subject`: وصف الخلل المُبلَّغ باختصار، مثال: "huntbug: نسبة الحضور تظهر 0%
   لمدرسة X") — هذه تُستخدَم كمعرِّف مرجعي، لا يعمل عليها وكيل تحقيق.
2. أربع مهام تحقيق، بندٌ لكل مسار، `metadata: {huntbugParent: "<معرِّف مهمّة التنسيق>"}` وعنوان
   يبدأ بـ`[huntbug#<معرِّف مهمّة التنسيق>]` (مثال: `[huntbug#12] المسار 1 — git bisect`) — هذا
   يحاكي "أب/تابع" بلا الاعتماد على ميزة غير موجودة في الأداة.

**بروتوكول التحديث الحيّ أثناء التحقيق (إلزامي لكل وكيل مسار، لا اختياري):**
- عند بدء العمل: `TaskUpdate` بـ`status: in_progress` و`owner` باسم الوكيل.
- **أثناء** التحقيق (لا فقط في النهاية): `TaskUpdate` بمفتاح `metadata` تصاعدي غير مكرَّر لكل
  تحديث (`progress_1`, `progress_2`, …) — قيمته سطر نصّي مختصر بالطابع الزمني وما اكتُشف
  للتوّ (`TaskUpdate` يدمج مفاتيح `metadata` لا يستبدلها بالكامل، فيتراكم سجل تقدّم فعلي بلا أداة
  "تعليق" مخصَّصة). هذا يُتيح للمالك مراقبة اللوحة حيّاً بلا استقصاء (polling) — هدف العقد الصريح.
- عند الانتهاء: `TaskUpdate` بـ`status: completed` و`description` مُستبدَلة بملخّص النتيجة النهائية
  للمسار (الدليل الملموس، لا وصفاً عاماً).

## 1) إطلاق المسارات الأربعة — بالتوازي، رسالة واحدة

أطلق 3-4 وكلاء (Agent tool، عدّة استدعاءات في نفس الرسالة — لا تسلسلياً) فور إنشاء اللوحة، كل وكيل
مقيَّد بمسار واحد فقط ولوحة `TaskUpdate` الخاصة به:

### المسار 1 — `git bisect` في `git worktree` معزولة (إلزامي، لا استثناء)

**لماذا معزولة:** `clasp push`/`clasp deploy` يعمل على محتوى القرص بصرف النظر عن حالة git — جلسة
موازية بفرع محلي غير مدموج على نفس المجلد المشترك يمكنها التصادم مع أي عملية على الشجرة الرئيسية
(حادثة موثَّقة: `_docs/2026-07-14-تصادم-نشر-جلسات-متوازية.md`،
`_planning/handoff-2026-07-18-android-schoolappyemen-play-release-v31.md`). لذلك **لا تلمس
`git bisect` الشجرة الرئيسية مطلقاً**.

**التنفيذ (أوامر git خام — لا أداة `EnterWorktree`):** `EnterWorktree` يُنشئ فرعاً جديداً من رأس
الفرع الافتراضي فقط، ولا يدعم الانتقال بين commits تاريخية عشوائية — غير صالح لمشي bisect. استخدم:
```bash
git worktree add --detach <path> origin/main   # مرة واحدة
git -C <path> checkout <sha>                    # لكل مرشّح، تكراراً
```
`_build/test-offline.js` و`_build/test-regression-guards.js` سكربتان ثابتان بلا وعي بـgit ولا
معاملات CLI — كلاهما يحسب `ROOT` عبر `path.resolve(__dirname, '..')`، فيعملان صحيحاً على أي نسخة
قرص طالما شُغِّلا من داخلها. لذا: `cd <path> && node _build/test-offline.js` (أو
`test-regression-guards.js`، أو فحص تكرار مُستهدَف يطابق البلاغ) عند كل `checkout`، وامشِ عبر
commits الأخيرة حتى تحديد أول commit فاشل. أبلغ اللوحة (`TaskUpdate`) بكل نقطة اختبار (SHA + نتيجة)
أثناء المشي، لا دفعة واحدة في النهاية.

### المسار 2 — إعادة إنتاج حيّة دنيا (ترتيب التصعيد الموثَّق حرفياً)

الهدف: أصغر تحقّق ممكن يميّز خللاً في الكود عن سبب بيانات/شبكة (نمط موثَّق: ملاحظة تشغيلية #4 —
عمود يظهر قيمة ثابتة/صفرية بسبب مصدر بيانات خاطئ لا مسار كود خاطئ). اتبع "ترتيب تصعيد قبل اللجوء
لمتصفّح" من جذر `CLAUDE.md` (§"Environment & Constraints") **بالترتيب**، ولا تتخطَّ خطوة:
1. `curl` عبر وسيط الـWorker (أبداً رابط `/exec` مباشر بلا كاش) + `node -e` لفحص الاستجابة نصياً
   (رؤوس/محتوى/كود حالة).
2. `_build/test-offline.js` أو مهارة `/gate` للتحقّق السلوكي البرمجي — بلا متصفّح إطلاقاً.
3. `chrome-devtools` MCP/`claude-in-chrome` **فقط كملاذ أخير** لتأكيد بصري يتعذّر الحصول عليه نصياً.

هذا التحقّق الدنيا يُحفَظ حرفياً — يُعاد تشغيله في §4 قبل إعلان الإصلاح.

### المسار 3 — سلامة البيانات + سياق عالمي/تعدد مستأجرين + كاش عميل قديم

ثلاثة أنماط سبب جذري حقيقية موثَّقة في هذا المستودع، افحص الثلاثة لا نمطاً واحداً فقط:
- **مصدر البيانات الفعلي/العمود الفعلي** لا مسار الكود فقط (نمط ملاحظة #4 — نسبة الحضور، المرجع
  الوحيد الصحيح ورقة `جلسات_الحضور` لا عدّ صفوف «الغياب»).
- **عزل تعدّد المستأجرين:** هل كل دالة API مكشوفة (بلا بادئة `_`) تفتح شيتاً خاصاً بمدرسة تستدعي
  `_resolveTenant`/`_setActiveTenant` في مطلعها؟ (ملاحظة #10، حادثة `getAttendanceForStudent`
  PR#260 — `_docs/2026-07-12-تحقق-عزل-المستأجرين-student.md`).
- **كاش/جلسة عميل قديمة بلا تحديث حيّ:** هل `localStorage`/`sessionStorage` تُستعاد حرفياً بلا نداء
  خادم يُحدِّث الحقول الحسّاسة/العلائقية؟ (ملاحظة #9 — تبديل حسابات الإخوة، ثلاث جولات إصلاح بدت
  فاشلة رغم نجاح كل نشر فعلياً).
- افحص أيضاً احتمال **ترميز بيانات مرحَّلة مختلف عن الكود الجديد** لنفس المفهوم (ملاحظة #13،
  `teacher/CLAUDE.md` بند 12) إن كان البلاغ يمسّ بيانات قديمة/مستوردة.

### المسار 4 — بيئة/لغة/تفويض

- **`oauthScopes`:** قارن `oauthScopes` الحالي في `appsscript.json` للتطبيق المتأثّر بما هو
  مُفوَّض فعلياً. إعادة تفويض عالقة بعد تغيّر مجموعة النطاقات حادثة متكرّرة موثَّقة 3 مرات (جذر
  `CLAUDE.md` ملاحظة 3 + `teacher/CLAUDE.md` بند 4، مفصَّلة في قسم "بوّابة تغيّر oauthScopes"
  بـ`/ship`/`/gas-pipeline`) — النشر وحده لا يُعيد التفويض، والعطل لا يظهر إلا عند أول استخدام لاحق
  للنطاق المتأثّر.
- **لغة/ترميز النظام:** لعرض نص عربي غير سليم، عالج السبب الجذري (locale/codepage النظام) بدل
  ترقيع العرض — إرشاد صريح في جذر `CLAUDE.md` §"Debugging Preferences".

## 2) توليف النتائج — يُجريه الوكيل المنسِّق نفسه (بلا وكيل خامس)

بعد عودة المسارات الأربعة، **الوكيل المنسِّق ذاته** (لا وكيل "حَكَم" إضافي) يقارن النتائج الأربع:
1. اقرأ نتيجة كل مسار (`TaskGet` لكل مهمّة تحقيق).
2. اختر سبباً جذرياً واحداً مدعوماً بأقوى دليل (commit محدَّد من bisect، فرق نصّي محدَّد من إعادة
   الإنتاج، إلخ — لا استنتاج ترجيحي بلا دليل مباشر).
3. **تحقّق صراحةً أن هذا السبب لا يناقض نتائج المسارات الثلاثة الأخرى** — إن وُجد تناقض ظاهري
   (مثلاً bisect يشير لكوميت لا علاقة له بمسار البيانات المكتشَف في المسار 3)، أبلغ المالك بالتناقض
   صراحةً بدل اختيار قسري لأحد المسارين.
4. أغلق مهمّة التنسيق (`TaskUpdate` — `status: completed`، `description`: السبب الجذري المختار +
   الدليل + كيف طابق/لم يناقض بقية المسارات).

## 3) الإصلاح — حلقة TDD الحالية لـ`/gas-pipeline` حرفياً، لا اصطلاحاً جديداً

**فرع مخصّص أولاً** — قاعدة `CLAUDE.md` الإلزامية #1 ("فرع لكل تغيير — لا دفع مباشر إلى `main`")
تنطبق بصرف النظر عن أي مهارة نشطة؛ `/huntbug` يكتب كوداً (اختبار الانحدار + الإصلاح)، فيلزمه فرع
(`fix/huntbug-<وصف-قصير>`) قبل أي `Write`/`Edit`.

ثم اتبع حلقة bugfix الموثَّقة في `/gas-pipeline` **حرفياً بلا اصطلاح مختلف**:
1. **اكتب اختباراً يُعيد إنتاج الخلل ويفشل فعلاً أولاً** — تحقّق بتشغيله أنه يفشل قبل أي تعديل على
   الكود. المكان حسب طبيعة الخلل (`_build/test-regression-guards.js` لثبات/مصدر بيانات،
   `_build/test-offline.js` لمنطق offline/sync، تحقّق DOM موثَّق بـ`_docs/regression-baseline/`
   لعرض مرئي).
2. **نفّذ الإصلاح** بناءً على السبب الجذري من §2 — لا تصليح أعراض.
3. **حلقة تكرار حتى تمرّ كل الاختبارات ذات الصلة** (`npm run guards && npm test`) — لا خروج عند
   أول فشل جزئي، ولا إعلان نجاح قبل مرور الاختبار الجديد تحديداً.
4. **الاختبار الجديد يبقى في المستودع دائماً** بعد نجاح الإصلاح — حارس تراجع دائم لهذا الخلل.

## 4) تأكيد قبل إعلان "مُصلَح" — إعادة تشغيل المسار 2 حرفياً

قبل إعلان الخلل مُصلَحاً: **أعِد تشغيل إعادة الإنتاج الحيّة/المحلية الدنيا من §المسار 2 بنفس
الخطوات** وتأكّد أنها الآن تمرّ (لا خلل ظاهر). لا يكفي مرور اختبار الانحدار الجديد وحده — التحقّق
المزدوج (اختبار مُقنَّن + إعادة إنتاج حيّة/محلية دنيا) هو معيار "مُصلَح" هنا.

## 5) التسليم — لا نشر، لا دمج، تسليم صريح فقط

`/huntbug` **لا يُشغِّل البوّابة الكاملة (`npm run gate`)، ولا يفتح PR، ولا يدمج، ولا ينشر أبداً** — هذه
خطوات `/gas-pipeline`/`/deliver` القائمة، لا تُكرَّر هنا. عند اكتمال §3-4 بنجاح، أبلغ المالك:

```
✅ إصلاح مؤكَّد — huntbug
السبب الجذري: <من §2>
الإصلاح: <الملف/الدالة>
اختبار الانحدار الجديد: <الاسم> (يمرّ الآن، فشل قبل الإصلاح — دليل: <سطر النتيجة>)
إعادة الإنتاج الحيّة/المحلية الدنيا (المسار 2): مُعاد تشغيلها، تمرّ الآن
الفرع: fix/huntbug-<وصف> — جاهز لـ/gas-pipeline أو /deliver لإتمام gate→PR→دمج→نشر
```

لا تفترض إذناً للمتابعة تلقائياً إلى `/gas-pipeline`/`/deliver` — التسليم يعني تسليم القرار للمالك،
لا استدعاءً تلقائياً للمهارة التالية.

## قواعد ملزمة (بلا استثناء)

- المسار 1 لا يلمس الشجرة الرئيسية مطلقاً — `git worktree` معزولة إلزامياً، بلا استثناء "خلل بسيط".
- كل وكيل مسار يُحدِّث `TaskUpdate` **أثناء** التحقيق (مفاتيح `metadata` تصاعدية)، لا في النهاية
  فقط — لوحة المهام مصدر مراقبة حيّ، لا تقرير نصّي مؤجَّل.
- التوليف (§2) يُجريه الوكيل المنسِّق نفسه — **لا وكيل "حَكَم" خامس** مهما بدا ذلك أدقّ.
- حلقة TDD (§3) تُنسَخ حرفياً من `/gas-pipeline` — لا اصطلاح اختبار مختلف مهما بدا أبسط لهذا الخلل
  تحديداً.
- إعادة تشغيل إعادة الإنتاج الدنيا (§4) إلزامية قبل إعلان "مُصلَح" — لا يكفي اختبار الانحدار وحده.
- `/huntbug` لا ينشر، لا يدمج، لا يفتح PR — ينتهي بتسليم صريح مكتوب لـ`/gas-pipeline`/`/deliver`،
  لا استدعاء تلقائي لهما.
