---
title: "التشخيص والتدريب"
url: https://docs.growamal.com/ar/guides/diagnostic-and-practice/
language: ar
---

# التشخيص والتدريب

تشكّل نظاما التشخيص والتدريب حلقة القياس التي يمر بها الطالب. تجمع جلسة التشخيص الإجابات
المصنّفة وتمررها إلى محرك الحساب الذي ينتج درجة θ (مثبّتة بالمعايرة) ومعيار الخطأ المرافق لها،
ثم يُغذّي هذا الناتج [محرك حالة المهارة](https://docs.growamal.com/ar/guides/skill-status-engine/) وصولاً إلى
[ملفات الطلاب](https://docs.growamal.com/ar/guides/student-profiles/) و[حزم التدخل](https://docs.growamal.com/ar/guides/intervention-bundles/).
يأتي التدريب بعد ذلك ليدير حلقة تكيّفية مبنية على نتائج التشخيص المكتمل.

يقع كلا النظامين في `modules/session`، بينما يقع محرك الحساب في `modules/engine`.

## جلسة التشخيص

### دورة الحياة

جلسة التشخيص (صفّ في `student_session` نوعه `diagnostic`، مع تفاصيله في `student_session_diagnostic`) هي
الحاوية المتغيّرة التي تتابع جلوس الطالب. قوائم التدريب ومجموعات التأكيد هما النوعان الآخران في الجدول نفسه. لا يمكن أن
تكون هناك أكثر من جلسة مفتوحة واحدة لكل طالب في كل دورة تقييم؛ يؤدي محاولة فتح جلسة ثانية
إلى إرجاع `409` مع معرّف الجلسة القائمة.

تمر الجلسة بأربع حالات:

```
active → paused → complete
             ↓
         abandoned
```

عند الوصول إلى حد 15 دقيقة من الوقت الفعّال، تُغلق الجلسة بـ`sessionEndReason: time_cap`؛ تصبح الحالة `complete` (لا توجد حالة `time_capped` مستقلة). يؤدي الإغلاق بواسطة المعلم إلى تعيين `sessionEndReason: teacher_stopped` وتصبح الحالة `abandoned`. يؤدي الإغلاق بخطأ داخلي إلى تعيين `sessionEndReason: error` وتصبح الحالة `abandoned`. لا توجد في الواجهة البرمجية الحالات `started` و`in_progress` و`finished` و`time_capped`.

سجل الحالات مضاف إليه فقط. يمكن تعديل رأس الجلسة نفسه (لأنه يجب تحديثه مع ورود الإجابات)، لكن
كل انتقال بين الحالات يُنشئ صفاً جديداً في `status_transition` (الكيان `student_session`). مسار التدقيق
لا يُحذف ولا يُعدَّل أبداً.

### بدء جلسة

```bash
curl -X POST https://localhost:3000/api/diagnostic-sessions/start \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "subSkillId": "PHON-01", "assessmentWindowId": "BOY" }'
```

يتطلب صلاحية `USE_DIAGNOSTIC_ENGINE`. يضع الخادم قفلاً استشارياً per `(org, studentProfileId)`
بحيث تُعالَج الطلبات المتزامنة لنفس الطالب تسلسلياً بدلاً من التسابق إلى قيد قاعدة البيانات.

### إرسال الإجابات

يقبل `POST /api/diagnostic-sessions/:id/responses` فقط `selectedOption`؛ لا يُرسل العميل
أبداً `isCorrect` ولا درجة سابقة. يقرأ الخادم الإجابة الصحيحة من بنك الأسئلة ويصنّف الإجابة
داخلياً. هذا ضمان أساسي للنزاهة: لا يمكن لحمولة استجابة مزوّرة أن ترفع درجة أو توجّه قيمة θ.

يُسجّل الخادم مهارة فرعية واحدة في كل مرة. في الجلسات متعددة المهارات الفرعية، يعيد العميل
استدعاء `/responses` مع `subSkillId` التالي بعد إغلاق المهارة الفرعية السابقة.

### حد الوقت

يُتابَع الوقت الفعّال (الإجمالي مطروحاً منه فترات الإيقاف المؤقت وإعادة التشغيل الصوتي) في
`cap.ts`. عند الوصول إلى 900,000 ملّي ثانية (15 دقيقة) أو تجاوزها، يُنهي استدعاء
`/responses` التالي الجلسة تلقائياً مع `sessionEndReason: time_cap`. لا يُعاقَب الطالب على الإيقاف
المؤقت أو إعادة الاستماع؛ الوقت الفعّال وحده هو ما يُحسب.

### الصوت أولاً للصف الأول

بالنسبة لطلاب الصف الأول، يقرأ الخادم `student.gradeLevel` لاختيار الأسئلة الصوتية. لا يقرأ
أبداً `class.grade` داخل وحدة الجلسة، يُفرض ذلك بفحص CI يُسمى `lint:session-grade-filter`.
إذا لم يتوفر سؤال صوتي للمهارة الفرعية، يكون `firstItemId` قيمته `null`؛ ومنذ 2026-09-07 تُترك هذه الجلسة على الخادم: يحمل الردّ أيضًا `noEligibleItem: true` و`state.status: "abandoned"`، ويحتفظ الصف بـ`sessionEndReason: "no_eligible_item"`، ويُرجع `POST /api/diagnostic-sessions/{id}/finish` عليها `404`. اعرض حالة «لا توجد أسئلة جاهزة الآن» ودع الطالب يبدأ لاحقًا؛ ولا تعاملها أبدًا كجلسة مكتملة. ولا تعود الجلسة إلى
سؤال نصي.

### المرونة في التخزين المحلي للمتصفح

تعرض كل جلسة طلابية جولة حالة/استئناف (القاعدة الإلزامية B.5). عند استدعاء
`POST /api/diagnostic-sessions/:id/resume`، يُعيد الخادم التحقق من الملكية والمستأجر ونافذة
24 ساعة من `lastTouchedAt` في قاعدة البيانات، لا من الرمز وحده. رمز مسروق لا فائدة منه
عبر الجلسات.

يُرجع `GET /api/diagnostic-sessions/:id/state` رمزاً موقّعاً (HMAC) يجب أن يخزّنه الطرف
الأمامي في `localStorage` أو `sessionStorage`. عند التحديث أو تبديل التبويب أو قفل الجهاز،
يُقدّم العميل الرمز إلى `/resume` لاستعادة الجلسة من نقطتها الدقيقة.

> **ملاحظة:** يُرجع `finish` قيمة θ والخطأ المعياري ضمن رمز منسوب للطالب. هذا هو **السطح الوحيد** الذي
> تظهر فيه θ في استجابة مصادق عليها بحساب الطالب، وهي مدخل لقرار المعلم. كل استجابة طلابية
> أخرى يُجرّد منها θ والخطأ المعياري وكفاية البيانات وحالة المهارة ومعلومات الملف والحزمة
> والطبقة التدريجية بواسطة المسلسِل القائم على القائمة المسموح بها.

### المسارات الستة للتشخيص

| الطريقة | المسار | الصلاحية |
|---|---|---|
| `POST` | `/api/diagnostic-sessions/start` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `GET` | `/api/diagnostic-sessions/:id/state` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `POST` | `/api/diagnostic-sessions/:id/resume` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `POST` | `/api/diagnostic-sessions/:id/responses` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `POST` | `/api/diagnostic-sessions/:id/finish` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `GET` | `/api/diagnostic-sessions/:id` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة أو قراءة معلم الفصل |

## المحرك (حساب θ)

وحدة المحرك (`modules/engine`) هي حلقة القياس. تقبل دفعة من الإجابات المصنّفة، وتطبق صيغة
الحساب المثبّتة بالمعايرة، وتكتب صفاً غير قابل للتعديل في `diagnostic_session`، وترجع θ
الجديدة والخطأ المعياري والسؤال التالي.

### لا نماذج لغوية في حلقة القياس

لا تدخل أي نموذج لغوي في حساب θ أو اختيار الأسئلة أو تصنيف الإجابات. الصيغة حتمية
ومثبّتة: المدخلات ذاتها تنتج دائماً θ متطابقة بتةً إلى 4 خانات عشرية (ضمان الإعادة V-6). تُخزَّن
θ كـ `Decimal(7,4)` بدلاً من float للقضاء على الاختلاف بين الأجهزة.

### اختيار δ بمسارين

لكل سؤال قيمة `deltaPrior` (محسوبة عند الاستيراد) وقيمة `deltaCalibrated` مستقبلية
(تكتبها WP-CAL). يستخدم المحرك δ المعيّرة حين تبلغ عتبة الثقة 300 استجابة مقارنة؛ دون ذلك
يعود إلى القيمة المبدئية. تُجمَّد نسخة من قيم δ المستخدمة على صف التدقيق حتى تقرأ الإعادة
ما استخدمه المحرك فعلاً، لا القيمة الحية في `item_bank` التي قد يُعيد تشغيل المعايرة كتابتها.

### اختيار الأسئلة (CAT)

يختار المحرك السؤال التالي بأقصى معلومات فيشر عند θ الحالية. تُفضّ التعادلات
أبجدياً وفق `itemId` لضمان الحتمية. الأسئلة المقدَّمة مسبقاً خلال الجلسة مستبعدة. لا توجد
نافذة صعوبة في مسار التشخيص؛ جميع الأسئلة المؤهلة للمهارة الفرعية تتنافس بمعلومات فيشر وحدها.

### المسارات الأربعة للمحرك

| الطريقة | المسار | الصلاحية |
|---|---|---|
| `POST` | `/api/engine/score` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `GET` | `/api/engine/sessions/{id}` | `USE_DIAGNOSTIC_ENGINE` + نطاق المنظمة |
| `GET` | `/api/engine/sessions/by-student/{studentId}` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `POST` | `/api/engine/replay/{sessionId}` | `RUN_BACKOFFICE` |

`replay` يُعيد تنفيذ مدخلات الجلسة المثبّتة دون كتابة أي شيء. هو مسار التدقيق V-6.

### الناتج يُغذّي محرك حالة المهارة

عند اكتمال التشخيص، يكتب الخادم شيئين: صفوف θ per-sub-skill (`student_assessment_result`)
وصف أدلة `screening_score` مبني على العدّ مُشتَق من الإجابات التي صنّفها الخادم. صف
`screening_score` هو ما تكتبه [جسر القياس](https://docs.growamal.com/ar/guides/measurement-bridge/) في جدول الأدلة
الخاص بمحرك حالة المهارة وما يستهلكه إعادة حساب المحرك في تشغيله التالي. يقرأ المحرك تلك
الأدلة إلى جانب اختبارات CBM وأنواع أدلة أخرى لينتج `SkillStatus` و`DomainStatus` لكل
مهارة فرعية ونطاق، لتقود تلك الحالات بدورها حلّ الملف وصولاً إلى توصية حزمة التدخل.

## التدريب التكيّفي (WP-05)

يُبذر التدريب من تشخيص مكتمل ويدير حلقة تكيّفية per-sub-skill.

### بذر قائمة التدريب

`POST /api/practice/queues/seed/:diagnosticSessionId` يبني قائمة تدريب (`student_session` نوعها `practice`) مرتبة من صفوف θ
للتشخيص المكتمل. تشمل المهارات الفرعية الضعيفة أو قيد المراقبة فقط (المهارات التي لا تحمل θ،
أي البيانات غير الكافية، مستبعدة وفق GSR-01). يُهيّئ البذر أيضاً `student_practice_band` دائماً
per-sub-skill مبتدئاً من θ التشخيص؛ إذا كانت الطبقة موجودة مسبقاً لتلك المهارة الفرعية تُترك
دون تغيير (قاعدة الاستمرارية).

في الموجة الأولى، تحمل كل قائمة مهارة فرعية واحدة بالضبط (الأضعف بحسب θ). حين يكون لدى
الطالب عدة مهارات فرعية ضعيفة، يُعيد بذر قائمة جديدة لكل مهارة بعد انتهاء السابقة.

### اختيار الأسئلة التكيّفي في التدريب

`GET /api/practice/queues/current/next-item` يُطبّق نافذة صعوبة θ ± 0.5 لوجيت لتضييق
المرشّحين قبل اختيار أقصى معلومات فيشر. هذه النافذة قيد خاص بالتدريب فقط؛ لا يملك محرك
التشخيص نافذة من هذا النوع. الأسئلة المقدَّمة مسبقاً في القائمة الحالية مستبعدة. تُشتقّ القائمة النشطة من ملف
المستخدم المصادق عليه؛ لا يوجد معامل `:studentId` في المسار، مما يمنع IDOR.

### إرسال الإجابات وتوجيه الطبقة

`POST /api/practice/queues/current/submit-response` يصنّف الإجابة ويحدّث θ ويضيف
صفاً في `practice_response`. حين يكتمل بلوك من 8 أسئلة على الأقل، تُطبَّق قاعدة التوجيه 80/60
على الطبقة الدائمة:

| دقة البلوك | الإجراء |
|---|---|
| 80% أو أكثر | رفع الطبقة |
| 60-79% | الإبقاء على الطبقة |
| أقل من 60% | خفض الطبقة |
| أقل من 60% عند طبقة `very_easy` | التوجيه إلى مهارة فرعية متطلَّبة (لا توجد درجة أدنى) |

حين تنخفض دقة البلوك إلى ما دون 60% وكان الطالب في طبقة `very_easy` بالفعل، يوجّه النظام
إلى مهارة فرعية متطلَّبة بدلاً من الخفض أكثر، لأن سلّم الطبقات لا يحمل درجة أدنى من `very_easy`.

تُكتب تغييرات الطبقة في `student_practice_band_history`. تستمر الطبقة عبر قوائم البذر المعاد
إنشاؤها؛ طالب يعود بعد أسبوع يبدأ من حيث توقف.

### استعادة الحالة في التدريب

`GET /api/practice/queues/current/state` يُرجع رمزاً موقّعاً (HMAC) كما هو الحال في
مسار حالة التشخيص. يخزّنه العميل ويقدّمه عند فتح الجلسة التالية لاستعادة الموضع في القائمة،
بنفس المرونة المطلوبة عند التحديث وتبديل التطبيق والقفل وانقطاع الاتصال والإغلاق القسري.

### المسارات الأربعة للتدريب

| الطريقة | المسار | الصلاحية |
|---|---|---|
| `POST` | `/api/practice/queues/seed/:diagnosticSessionId` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `GET` | `/api/practice/queues/current/next-item` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `POST` | `/api/practice/queues/current/submit-response` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |
| `GET` | `/api/practice/queues/current/state` | `USE_DIAGNOSTIC_ENGINE` + طالب الجلسة |

## ما لا يصل إلى الطالب

يُجرّد المسلسِل القائم على القائمة المسموح بها (`toStudentSessionDTO`) كل استجابة طلابية من:

- θ والخطأ المعياري
- `dataSufficiency`
- `SkillStatus` و`DomainStatus`
- معرّفات الملف الأساسي والمُعدِّل والعلامات الفرعية
- معلومات الحزمة والطبقة التدريجية
- تفاصيل نطاق الصعوبة الداخلية

استجابة `finish` والملخص الموجَّه للمعلم هما السطحان الوحيدان المجاوران لـ θ، والملخص يحذف
θ الخام عمداً.

## إعادة التشخيص

إعادة التشخيص هي جلسة جديدة في نافذة تقييم لاحقة، لا تفريعة عن الآلية الأصلية. تسلك المسار
ذاته للمُنسِّق، لكن مع حارسَين إضافيَّين عند البداية.

**بوابة الـ14 يوماً.** يتحقق `POST /api/diagnostic-sessions/start/re-diagnostic` من مرور 14 يوماً
على الأقل منذ آخر تشخيص مكتمل لنفس الطالب والدورة ذاتها (يُقاس من `finishedAt` لا من
`startedAt`). يُعيد الطلب داخل البوابة `409` مع `reason: rediag_too_soon` وطابع زمني
`earliestAllowed`. إذا لم يكن هناك تشخيص سابق مكتمل، تُعفى البوابة وتُفتح الجلسة بصورة
عادية.

**أرشفة قائمة التدريب السابقة.** قبل فتح الجلسة الجديدة، تُؤرشَف جميع قوائم التدريب المفتوحة
للطالب (يُضبط `archivedAt`، وتتغير الحالة إلى `abandoned`). تمر الأرشفة عبر مسار الكتابة
الأحادي `mutateQueue`. إذا نشطت قبلها ثابتة الجلسة الواحدة (جلسة مفتوحة موجودة فعلاً للدورة)،
تُتخطى الأرشفة كليًا لمنع فقدان بيانات خطة التدريب بصمت.

المقارنة بين الجلسة السابقة والجديدة شأن قرائي تتولاه وحدة [التقارير](https://docs.growamal.com/ar/guides/reporting-and-parent-pdf/).

## الأنظمة المرتبطة

- [محرك حالة المهارة](https://docs.growamal.com/ar/guides/skill-status-engine/): يستهلك صفوف θ من التشخيصات المكتملة
- [تسليم المهام](https://docs.growamal.com/ar/guides/task-delivery/): يقدّم محتوى الأسئلة لكل معرّف سؤال
- [تصنيف المهارات](https://docs.growamal.com/ar/guides/skills-taxonomy/): يُعرّف المهارات الفرعية الـ80 التي يقيسها التشخيص
- [مراقبة التقدم](https://docs.growamal.com/ar/guides/progress-monitoring/): يتابع نتائج التدريب عبر الزمن
- [البدء السريع](https://docs.growamal.com/ar/getting-started/): الإعداد الكامل للمطوّر

## نوافذ التقييم (2026-09-09)

يُعرض التقييم على الطفل فقط داخل نافذة تقييم مفتوحة. يخبر `GET /api/student/today-plan` أيّها (`screening: { window, source }` — يكون `source` هو `class_trigger` عندما تفتحه المعلّمة لصفّها، وإلّا النطاق الذي ينطبق تقويمه) ويُرجع `null` عندما لا شيء مفتوح أو عندما أكمل الطفل تلك النافذة هذه السنة الدراسية. لم يعد `POST /api/diagnostic-sessions/start` يحتاج `screeningCycle`: أغفله فيحدّد الخادم النافذة بالطريقة نفسها؛ وينال الطالب الذي يسمّي نافذة غير مفتوحة `409 window_mismatch`، وعندما لا شيء مفتوح `409 no_open_window` (لا تُنشأ جلسة — اعرض حالة هادئة «لا يوجد تقييم مفتوح الآن»). تسجّل الجلسة `screeningSource`. يضبط المشرفون التواريخ عبر `/api/admin/screening-windows`؛ وتفتح المعلّمات تقييم الصف عبر `/api/classes/{classId}/screening-triggers`.
