Skip to Content

سجل التغييرات

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

أقسام جلسة التقييم (WP-STT)، 2026-10-15

لا عملية مُضافة أو محذوفة. ثلاث استجابات في جلسة التقييم تحمل حقولًا جديدة إضافية (في الاستجابة فقط) لأزرار أقسام الطالب:

  • sections في StartDiagnosticResponse (POST /api/diagnostic-sessions/start) وStartReDiagnosticResponse (POST /api/diagnostic-sessions/start/re-diagnostic) وDiagnosticStateResponse (GET /api/diagnostic-sessions/{id}/state): مصفوفة { key, total }[] بترتيب النموذج، وkey واحد من text1 أو text2 أو words أو spelling أو roots. تُحسب من خطة النموذج المثبّتة للجلسة. الجلسة التي ليس لها خطة نموذج تُرجع [].
  • state.sectionKey في كل استجابة تحمل StudentSessionState (البدء، بدء إعادة التقييم، الحالة، الاستئناف، الإجابة): قسم السؤال الحالي، أو null.
  • الحقلان للعرض فقط، وليسا درجة.

«إجراء التقييم» — صفحة التقييم للمعلّم وإعادة القياس، 2026-10-14

ثلاث عمليات جديدة (من 452 إلى 455 عمليّة). الترحيلان 20261014100000_measurement_void و20261014200000_skill_snapshot_no_evidence_row. النشر: شغّل الترحيلين؛ لا شيء يُزرع أو يُنشر.

  • getTeacherTaqyeem ‏GET /api/teacher/classes/{classId}/taqyeem?window= (الوسم teacher-views، والشكل TdvTaqyeem؛ للمعلّم، والصفّ من صفوفه، دون تسجيل وصول). قراءة واحدة لصفّ وفترة (إن لم تُحدَّد فالفترة الافتراضية للصفّ): windows وwindowState (‏openTrigger أو null، وcanOpen) وblueprint الصفّ (‏status ‏ok / not_screened / legacy_skill_cell / catalog_gap وmeasures) وsummary (‏enrolled وcomplete وremaining لكلّ خانة) وdayPlan (لكلّ خانة: studentCount وminutesPerStudent وtotalMinutes) وstudents[] بأربع خانات — digital وoral_text وoral_familiar_words وoral_pseudowords — لكلّ منها { status, attemptId, at, result, restarts }. قيم status: ‏done وin_progress وnot_started وstopped وrestarted_pending وunavailable. أعداد فقط، بلا نسبة للصفّ، وبلا رمز دخول الصفّ. ‏404 لصفّ ليس من صفوف المستدعي.
  • voidTaqyeemAttempt ‏POST /api/teacher/classes/{classId}/taqyeem/void (الوسم measurement-void؛ للمعلّم، RECORD_TEACHER_ACTION). الجسم { kind, targetId, reason }: ‏kind ‏digital_sitting / oral_text / oral_word_list، وreason ‏student_not_ready / technical_interruption / started_by_mistake / other (بلا نصّ حرّ). ‏201 يُعيد سطر الإعادة (‏academicYear وevidenceWindow هما سنة المحاولة وفترتها، وendedActiveSitting صحيح حين أُنهيت جلسة رقمية مفتوحة). المحاولة تبقى محفوظة ولا تُحتسب في القرارات والاتجاهات والقراءات؛ ‏404 خارج النطاق، و409 ‏already_voided، و422 ‏not_a_window_sitting. المحاولة البديلة تُربط بسطر الإعادة في الخادم (‏supersedesVoidId)؛ لا حقل جديد على العميل.
  • getStudentReadingSheet ‏GET /api/classes/{classId}/students/{studentId}/reading-sheet.pdf?passageId= (الوسم reading-assessment؛ لمعلّم الصفّ، والطالب مسجَّل فيه). ورقة النصّ A4 لطالب واحد بصيغة application/pdf دون رمز QR؛ لا تكتب دفعة ولا بندًا مخطّطًا ولا ملفًّا مخزَّنًا (تجاوز المشرف العامّ يُسجَّل في التدقيق، كما في كلّ مسارات الوحدة). ‏404 خارج النطاق.

أشكال تغيّرت:

  • getAdminAuditLog ‏GET /api/admin/audit-log: يُضاف measurement_void إلى eventType (وإلى kind في السطر)؛ وأسطر الإعادة تحمل الحقلين الاختياريّين voidKind وvoidReason، وactorUserId = المعلّم، وtargetStudentId وtargetClassId، والمعرّف void:<int> الذي يقرؤه أيضًا getAdminAuditEvent ‏GET /api/admin/audit-log/{id}.
  • markOrfError ‏POST /api/orf/assessments/{id}/mark و**stopOrfAssessment** ‏POST /api/orf/assessments/{id}/stop: ‏409 جديد (السبب voided) لجلسة أُعيدت.
  • getSkillStatus ‏GET /api/sse/students/{id}/skill-status: ‏adrRuleId وssrRuleId قابلان لأن يكونا null. يكونان null معًا (مع doNotDecideYet صحيح) فقط في سطر «لا أدلّة» الذي يُكتب حين أُعيدت كلّ محاولات الفترة؛ اقرأ المهارة حينها غير مُقيَّمة.

راجع مرجع الواجهة البرمجية للأشكال الكاملة.

حذف جداول العيّنة المجهولة، 2026-10-09

لا تغيير في الواجهة البرمجية. يحذف الترحيل 20261009220000_drop_teaser_tables الجداول teaser_item_set وteaser_session وteaser_lead والنوع TeaserSessionStatus. لم يُكتب فيها شيء منذ إيقاف العيّنة المجهولة في اليوم نفسه.

  • لم يعد محو بيانات البالغين يحذف صفوف العيّنة، فلم تعد counts تضمّ المفتاح teaser_lead.
  • لا يُحتفَظ بأيّ صفّ. تُحذف الصفوف التي تحمل بريدًا إلكترونيًا أو رقم واتساب مع باقي الصفوف، دون تصدير.

إيقاف دعوة تسجيل مفتاح المرور، 2026-10-09

لا عمليات جديدة ولا محذوفة (452 عمليّة). يُحذف حقلان كانا يغذّيان وحدهما دعوة تسجيل مفتاح المرور بعد الدخول، وقد أزالتها الواجهة:

  • MeResponse.passkey ({ registered, promptSuppressed }) لم يعد يُعاد من getMe ‏GET /api/auth/me.
  • passkeyPromptSuppressed يخرج من UserPreferencesResponse (‏GET / PATCH /api/users/me/preferences) ومن PatchUserPreferencesBody. جسم الطلب صارم، فالعميل الذي ما يزال يرسل المفتاح يتلقّى 400.
  • ترحيل 20261009140000_drop_passkey_prompt_suppressed يحذف العمود user_preferences.passkeyPromptSuppressed.
  • دون تغيير: الدخول بمفتاح المرور وإدارته (/api/auth/webauthn/*).

إيقاف العيّنة المجهولة وإزالة بقايا العرض التجريبي، 2026-10-09

حُذفت ثلاث عمليات (الوسم teaser): postTeaserSession ‏POST /api/teaser/sessions وpostTeaserFinish ‏POST /api/teaser/sessions/{id}/finish وpostTeaserLead ‏POST /api/teaser/leads تُعيد الآن 404. ينخفض الإجمالي المنشور من 455 إلى 452 عمليّة. توقّفت الصفحة الرئيسية عن عرض أداة «جرِّب سؤالًا» حين انتقل المسار ”/” إلى الصفحة الرئيسية الجديدة، ولم يعد أيّ جزء آخر يستدعي هذه المسارات.

  • حُذف معها: حدّ المعدّل teaser_start والأمر pnpm seed:teaser ودليل «واجهة برمجة العيّنة المجهولة».
  • لم يعد الاتحاد UserProfile يضمّ العضو DEMO_ADMIN، ولم تعد مسارات المستخدمين تذكر DEMO_ORG_NO_OUTBOUND. لم يكن أيّ منهما قابلًا للإرجاع منذ إيقاف مستأجر العرض التجريبي في 2026-09-23. وحُذف دليل «مستأجر العرض التجريبي» كذلك.
  • لا ترحيلات. تبقى الجداول teaser_item_set وteaser_session وteaser_lead كما هي دون كتابة جديدة إلى أن يُتّخذ قرار منفصل بشأن صفوفها. ما يزال محو بيانات البالغين يحذف صفّ teaser_lead الذي يحمل عنوان الشخص.

قوائم الكلمات — القوائم الشفويّة لكلّ صفّ وفترة، 2026-10-08

ثماني عمليات جديدة (الوسم admin-word-lists؛ لمشرف النظام العامّ فقط؛ كلّ نداء يكتب سجلّ التجاوز audit_event). لا ترحيلات.

  • listAdminWordLists GET /api/admin/word-lists?organizationId= — كلّ القوائم في النطاق (العامّة وحدها بلا معامل؛ العامّة + المؤسّسة عند تسميتها)، بكلّ الحالات والإصدارات مع assessmentsCount؛ وcells = كلّ (صفّ × مهارة × فترة) تُقاس بحسب قواعد الصفّ، مع min / max وpickedListId (القائمة التي يُقدَّم بها معلّم هذا النطاق: قائمة الفترة أوّلًا ثمّ «ALL»؛ قائمة المؤسّسة قبل العامّة؛ ثمّ أحدث إصدار)؛ وskills بتسمياتها للمعلّم.
  • getAdminWordList GET /api/admin/word-lists/{id} — القائمة مع versions (المعرّف نفسه، النطاق نفسه).
  • validateAdminWordList POST /api/admin/word-lists/validate — فحص جافّ بقواعد الاستيراد نفسها (validateWordList + فحص التكرار والتقاطع بين الصفوف، صار checkWordListAgainstScope): { ok, reject?, warnings } بلا كتابة.
  • createAdminWordList POST /api/admin/word-lists — الإصدار 1 مسوّدة؛ publish (افتراضيًّا true) يجعلها مفعّلة في المعاملة نفسها. 422 بشكل الفحص عند الرفض؛ 409 external_id_taken.
  • patchAdminWordList PATCH /api/admin/word-lists/{id} — المسوّدة في مكانها؛ القائمة المفعّلة → إصدار جديد مفعّل مع إيقاف المصدر؛ الموقوفة → مسوّدة جديدة. ifVersion → 412 stale. الردّ يحمل madeVersion.
  • publishAdminWordList / retireAdminWordList / restoreAdminWordList POST /api/admin/word-lists/{id}/publish|retire|restore — 409 invalid_state | newer_version_operational | another_version_operational؛ الإيقاف يعيد leavesCellEmpty.
  • تغيير: pickListsForWindow (قراءة المعلّم GET /api/word-lists) يقدّم قائمة المؤسّسة على العامّة عند تساوي رتبة الفترة. وDTO المشرف يحمل readingNoteAr، ملاحظة قاعدة القراءة التي يراها المعلّم.

بناء التقييم — معاينة الجلسة وتعديلها لكلّ مؤسّسة ومدرسة، 2026-10-08

عمليتان جديدتان (GET /api/admin/taqyeem/preview وPUT /api/admin/taqyeem/forms/{formId}/positions؛ الوسم admin-taqyeem؛ لمشرف النظام العامّ فقط). لا ترحيلات.

  • previewTaqyeem (organizationId إلزامي، schoolId?، grade 1–4، window BOY|MOY|EOY): الجلسة التي يجلس لها طالب يسيّرها لأوّل مرّة في هذا النطاق — الخليّة بمصدرها (global | org | school) ونوعها (measures | skills | not_screened | unset)، وخطّة الجلسة نفسها التي يبنيها بدء الجلسة (النموذج المختار، ترتيب الأسئلة بـformPosition، موضع الاستراحة، configReleaseId)، وكلّ سؤال بالإسقاط نفسه الذي يُرسَل للطالب (ServedItem) مع كتلة authoring (الإجابة الصحيحة) وmeta (organizationId، updatedAt لـ If-Match، المقياس، الموضع)، والقطع، والمقاييس بأعدادها، وwarnings (no_operational_form، invalid_cell بسبب buildMeasurePlan حرفيًا، provisional_scoring_table، legacy_cell، thin_pool، alternate_form، not_screened، unset). لا يكتب شيئًا سوى سجلّ تجاوز المشرف (audit_event)؛ Cache-Control: no-store. ترتيب الخيارات في المعاينة بمفتاح ثابت (taqyeem-preview) فيختلف عمّا يراه طالب بعينه؛ الأسئلة وتسلسلها متطابقان.
  • moveTaqyeemFormPositions (الجسم { moves: [{ itemId, formPosition, ifMatch }] }، 1–60): إعادة ترتيب أسئلة النموذج داخل المقياس نفسه (تبديل مواضع المجموعة نفسها فقط)، بمعاملة واحدة عبر مسار تعديل المحتوى نفسه (item_revision لكلّ سؤال منقول، الصورة السابقة { formPosition }). 412 stale لسؤال تغيّر منذ القراءة، 409 concurrent_move، 422 not_a_permutation | cross_measure | item_not_in_form، 404 نموذج خارج النطاق. الرابط الوسيط إيجابي (formPosition + 1000000) لأنّ قيد item_bank_content_role_fields يمنع الموضع السالب.
  • لا تغيير في PATCH /api/items/{id} ولا في مخطّط التقييم الأوّلي؛ الصفحة تستخدمهما كما هما. تغيير داخلي: servedItem / authoringItem انتقلا إلى items/served-projection.ts بلا تغيير في الإخراج.

رابط دخول الصف صالح سنة كاملة، 2026-10-06

لا عملية جديدة ولا تغيير في الشكل. صار loginCodeExpiresAt في GET /api/classes وPOST /api/classes وGET /api/classes/{classId}/login-cards وPOST /api/classes/{classId}/login-code/rotate يقع بعد 365 يومًا من إصدار الرمز أو تجديده (كان 30)، فيبقى الرابط المدفوع إلى أجهزة المختبر صالحًا طوال العام الدراسي. إنشاء الصف واستيراد القوائم والانتقال إلى السنة التالية تضبط تاريخ الانتهاء من الثابت نفسه الذي يستخدمه التجديد. الترحيل 20261006100000_class_code_ttl_365_days يمنح الرمز الحالي لكلّ صف فعّال في السنة الدراسية النشطة لمؤسسته سنة كاملة من تاريخ النشر، ويجعل القيمة الافتراضية للعمود 365 يومًا. أما الرمز الذي استُبدل بتجديد، والصف المحذوف، وصف سنة مغلقة، فتبقى على تاريخ انتهائها القديم، فيظلّ الرابط القديم إليها يعيد 410. ما زال المعلّم يجدّد الرابط يدويًا إذا تسرّب، وتعرض لوحة المعلّم الآن تاريخ الانتهاء ما دام أبعد من 30 يومًا.

رمز الطالب من رقمين ودائم؛ ورمز الصف ينتهي، 2026-10-04

عملية جديدة واحدة وعدّة عمليات تتغيّر في شكلها (جديد POST /api/classes/{classId}/login-code/rotate؛ وتتغيّر POST /api/auth/student/quickcode وGET /api/auth/student/class-preview وGET /api/classes وGET /api/classes/{classId}/login-cards وأجسام طلب رمز الطالب واستجابته).

  • رمز الطالب. صار quickCode رقمين، من 01 إلى 99، فريدًا بين طلاب الصف الفعّالين (يتّسع الصف لـ 99 طالبًا كحدّ أقصى) ولا ينتهي أبدًا. لم يعد quickCodeExpiresAt يُعاد أو يُكتب. والرمز نفسه هو كلمة مرور الدخول المنزلي. حُوِّل كلّ الطلاب الحاليين بسكربت لمرة واحدة (convert:student-codes-2-digit)؛ ويجب إعادة طباعة كلّ البطاقات المطبوعة.
  • رمز الصف. يحمل Class.loginCode الآن loginCodeExpiresAt (30 يومًا؛ يضيفه ClassResponse واستجابة بطاقات الدخول). POST /api/classes/{classId}/login-code/rotate (rotateClassLoginCode؛ الجسم { onlyIfExpired? }؛ الصلاحية MANAGE_CLASS_STUDENTS أو MANAGE_ORG؛ 10 تجديدات كلّ 15 دقيقة للمستخدم) يصدر رمزًا جديدًا بمدّة جديدة وينهي الرابط القديم فورًا؛ ويكتب كلّ تجديد سجلًا في AuthEventLog من النوع class_login_code_rotated (detail: manual أو expired_on_copy). وonlyIfExpired هو التجديد التلقائي عند النسخ، ولا يفعل شيئًا إذا كان الرمز ساريًا.
  • الدخول. يُرفض رمز الصف المنتهي كالرمز المجهول (401 QUICKCODE_INVALID_OR_EXPIRED). وGET /api/auth/student/class-preview يجيب 410 CLASS_CODE_EXPIRED، وتعرض صفحة الطالب «انتهى هذا الرابط، اطلب الرابط الجديد من معلّمك». وصيغة classId المباشرة لدخول الطالب مرفوضة في الإنتاج. وصار قفل الدخول المنزلي وللبالغين 10 محاولات فاشلة كلّ 15 دقيقة (كان 5).

تجربة المعلّمة الجديدة — الإصدار الأوّل، 2026-10-01

لا عملية جديدة؛ تتغيّر واحدة في سلوكها.

  • المفتاح. يُنشر الإصدار بـTEACHER_V3_ORGS="*"، فتعيد GET /api/auth/me القيمة features.teacherV3: true لكلّ معلّم في كلّ مؤسسة. لا تغيير في العقد؛ القيمة "" هي الرجوع خلال هذا الإصدار.
  • تقرير وليّ الأمر. حين يطلب معلّمٌ POST /api/parent/pdf/{childId} يُكتب سطر واحد في student_data_access_log (export_pdf، طالب واحد، دون معرّفه) قبل الملفّ؛ وإن تعذّرت الكتابة يُعاد 500 «Export could not be recorded» دون ملفّ. وليّ الأمر والمسؤول لا يكتبان شيئًا.
  • التفضيلات. يقرأ تطبيق الويب GET /api/users/me/preferences مرّة عند بدء الجلسة لكلّ الأدوار البالغة، ويُعيد التباين وخطّ القراءة إلى إعداد الجهاز عند الخروج. لا تغيير في العقد.

يوم التدريب، 2026-10-01

عملية جديدة واحدة؛ وتتغيّر خمس (الجديدة GET /api/practice/students/{studentId}/training-sessions/{trainingSessionId}؛ وتتغيّر GET /api/practice/students/{studentId}/training-sessions وGET /api/reports/students/{id}/sessions/{kind}/{sessionId} وGET /api/practice/queues/current/next-item وPOST /api/practice/queues/current/submit-response وGET /api/practice/queues/current/state؛ أُعيد توليد openapi:check، 394 مسارًا). الترحيلات 20261001310000 و20261001310100. النشر: نفّذ الترحيلات، ثمّ config:publish، ثمّ حوّل الحركة، ثمّ seed-main. تكتب الترحيلات أيضًا قواعد اليوم وقواعد الخطوات المساعدة الـ19 وأعمدة الخطوات المساعدة في سياسات المستويات، فيعمل يوم التدريب قبل تنفيذ البذرة.

  • يوم التدريب. يُخطَّط يوم قائمة التدريب بالمستويات مرّة واحدة حين يُفتح (أوّل طلب للسؤال التالي أو أوّل إجابة في اليوم المدرسي)، ويُحفظ مع إصدار الإعدادات وتوقيت المدرسة: أهداف اليوم (هدف واحد افتراضيًا يُختار بالتناوب، وثانٍ فقط لإكمال اليوم)، وعدد الأسئلة (3 تمارين × 4، ولا يزيد أبدًا على ما يستطيع مستوى الطالب تقديمه)، وحصّة الخطوات المساعدة، وسؤال ختام واحد، وحدّ 17 دقيقة من الوقت الفعلي. الأعداد في صفّ engine_parameters المسمّى training_session_rules وفي صفوف training_level_policy (مؤقّتة). تاريخ التدريب هو اليوم المحلّي للمدرسة (Asia/Amman للأردن، وAsia/Hebron لفلسطين).
  • الأسئلة الباقية. صار AssignTrainingResponse.itemCount (الإرسال) و«الأسئلة الباقية» للطالب يعدّان كل أهداف التدريب في القائمة، كل سؤال مرّة واحدة، ومعه سؤال ينتظر محاولته الثانية. لا تغيير في الشكل.
  • قائمة أيّام التدريب. تضيف صفوف GET /api/practice/students/{studentId}/training-sessions الحقل id (معرّف اليوم)، وtargets (skillId وskillLabelAr وlevelNumber وlevelNameAr لكل هدف مخطّط، بترتيب الخطّة، في المستوى الذي فُتح عليه اليوم)، وsupportSteps (الخطوات المساعدة التي ظهرت في ذلك اليوم)، وexitDone (أُجيب عن سؤال الختام)، وansweredCount (عدد الأسئلة التي أجاب عنها في ذلك اليوم: أسئلة التدريب وسؤال الختام، سؤالًا سؤالًا، بلا إجابات الخطوات المساعدة). الأربعة null في يوم فُتح قبل مستويات التدريب.
  • يوم تدريب واحد. يعيد GET /api/practice/students/{studentId}/training-sessions/{trainingSessionId} (getStudentTrainingDay) الحقول id وdate وtimeZone وleveled وplannedExercises وquestionsPerExercise وtargets (لكل هدف questionsAnswered وfirstTryCorrect وsecondTries وhintedAnswers وsupportAnswers) وsupportSteps (id والهدف ومستواه وsupportSkills وfiredAt وanswered وcorrect، من الأقدم) وexit (planned وanswered وcorrect، أو null) وended وendReason (done أو cap أو window_closed، وnull ما دام اليوم مفتوحًا) وfeedback وfeedbackAt. الوصول: معلّمة أحد صفوف الطالب أو مالكة مجموعة دعم هو فيها؛ وفريق العمل على مستوى المؤسسة. اليوم المجهول أو يوم طالب آخر أو الطالب من خارج مؤسسة المستدعي 404؛ والطالب من المؤسسة الذي لا تدرّسه المعلّمة 403؛ وtrainingSessionId الذي ليس uuid 422.
  • تفاصيل الجلسة. يضيف GET /api/reports/students/{id}/sessions/{kind}/{sessionId} الحقل trainingGroups في قائمة تدريب بالمستويات: الإجابات مجمّعة حسب هدف التدريب (targetSkillId وtargetLabelAr وlevelNameAr: مستوى أحدث إجابة في الهدف)، ثمّ حسب role (ordinary وretry وsupport وexit، ولكلٍّ labelAr وanswered وcorrect). إجابة الخطوة المساعدة تبقى تحت الهدف الذي ساعدت عليه؛ ومهارتها لا تكون أبدًا صفًّا في skills. null في كل جلسة أخرى.
  • ردود التدريب. تضيف ردود السؤال التالي والإجابة والحالة الحقل step (kind بقيمة target أو bridge أو exit؛ وstartsBridge؛ وstrategyPromptAr أو null). ويضيف hint في ردّ الإجابة الحقل kind (item أو light_hint أو clearer_hint أو generic)، ويضيف ردّ الإجابة explanation ({ textAr } بعد الخطأ الثاني، أو null). ويضيف training الحقلين phase (practice أو exit أو done) وexit (planned وdone). لا يحمل أيّ ردّ للطالب مستوى التدريب ولا اسمه ولا نمط السؤال ولا رمز القاعدة ولا المهارة الداعمة ولا صنف الترتيب.
  • الخطوات المساعدة. حين يخطئ الطالب في سؤالين مختلفين من المقياس والنمط نفسيهما في يوم واحد، يحصل على خطوة مساعدة قصيرة من جدول training_bridge_rule (19 صفًّا، تُفحص عند النشر)، ثمّ يعود إلى هدفه. لا خطوات في المستويين 3 و4، وخطوة واحدة في كل مرّة، ضمن حصّة اليوم. كل خطوة تظهر تُسجَّل صفًّا لا يُعدَّل في training_bridge_episode، ومعها جملة مقدّمتها (يعرض strategyPromptAr تلك الجملة نفسها). إجابات الخطوات المساعدة لا تغيّر المستوى أبدًا، ولا تُحسب في أسئلة اليوم ولا في سؤال الختام، ولا تطلق تنبيه تدريب، ولا تكتب دليلًا ولا حالة.
  • قوائم تدريب المكتبة. قائمة التدريب من مكتبة الجلسات التي فيها عدّة مهارات فرعية صارت تقدّم كل مهاراتها، لا الأولى فقط.
  • تطبيق الويب. يرى الطالب مقدّمة قصيرة قبل الخطوة المساعدة، وتلميحًا أوضح، وشرحًا قصيرًا بعد الخطأ الثاني، و«السؤال الأخير» في شريط الخطوات؛ وأُزيل سؤال المزاج في نهاية الجلسة. وتعرض بطاقة «التدريب» للمعلّمة مهارات كل يوم ومستوياتها، وعدد الأسئلة المُجابة («أجاب عن n سؤالًا»)، و«خطوات مساعدة: n» و«سؤال الختام ✓»، وتجمع تفاصيل الجلسة يوم التدريب حسب الهدف بعنوان «المهارة · المستوى». ثلاث عبارات جديدة للطالب تحتاج تسجيلًا (bridge-intro وlast-question وback-to-training).

مستويات التدريب وتنبيهات التدريب، 2026-10-01

ثلاث عمليات جديدة؛ وتتغيّر ثلاث (الجديدة GET /api/training/students/{studentId}/levels وGET /api/training/alerts وPOST /api/training/alerts/{alertId}/acknowledge، بالوسم training-progress؛ وتتغيّر GET /api/reports/students/{id}/sub-skill-report وGET /api/reports/students/{id}/session-results وGET /api/reports/students/{id}/sessions/{kind}/{sessionId}؛ أُعيد توليد openapi:check، 393 مسارًا). الترحيلات 20261001300000 و20261001300100 و20261001300200. النشر: نفّذ الترحيلات، ثمّ config:publish، ثمّ حوّل الحركة، ثمّ seed-main. تكتب الترحيلات صفوف القواعد أيضًا، فيعمل التدريب قبل تنفيذ البذرة.

  • مستويات التدريب. صار إرسال المعلّمة «تدريب» يبذر قائمة تدريب بالمستويات: يتدرّب الطالب على كل هدف (مقياس رقمي بمهارته الحاملة، أو مهارة منفردة) في مستوى من جدول training_level (1 تأسيس، 2 تعزيز، 3 تطبيق، 4 إثراء). يبدأ المستوى من أحدث تقييم هذا العام الدراسي (أو من فحص أعمق اكتمل بعده)، ويصعد بعد 80 % صحيحة على الأقل من آخر 8 إجابات محسوبة في يومَي تدريب مختلفين على الأقل، وينزل بعد كتلتين مغلقتين متتاليتين من 8 إجابات كلّ منهما دون 60 %. الإجابة المحسوبة محاولة أولى مستقلّة بلا تلميح، غير مستبعدة وغير سريعة جدًّا. لا يصل شيء عن المستويات إلى واجهة الطالب البرمجية. الأعداد في صفّ engine_parameters المسمّى training_progression (مؤقّتة)؛ وleveledTrainingEnabled: false يُبقي القوائم الجديدة على مسار المستويات القديم (band).
  • المستويات. يعيد GET /api/training/students/{studentId}/levels القيمة { studentId, academicYear, levels }. في كل صفّ skillId وskillLabelAr وmeasureCode وlevel (number وnameAr) وsince (يوم مدرسي YYYY-MM-DD) وstartedFrom (screen أو experience_type أو backtrack) وlastMove (direction بقيمة up أو down أو rebaseline، وat، وfromLevel) أو null، وopenAlerts (alertId وkind وacknowledged). تبقى القائمة فارغة حتى يبدأ إرسالٌ التدريبَ بالمستويات. الطالب الذي لا يصل إليه المستدعي 404؛ والدور الذي لا يملك VIEW_OWN_CLASSES ولا RUN_BACKOFFICE 403.
  • التنبيهات. يأخذ GET /api/training/alerts واحدًا فقط من classId أو groupId (وإلا 422 VALIDATION_ERROR) وstatus (open افتراضيًا، أو all). الصفوف من الأحدث، على طلاب النطاق الحاليين: alertId وstudentId وfullNameAr وskillId وskillLabelAr وmeasureCode وlevelNumber وlevelNameAr وkind وtitleAr وmessageAr وraisedAt وacknowledgedAt وstatus (open أو acknowledged أو resolved) وevidence (sessions بالتاريخ وعدد الإجابات المحسوبة والصحيحة؛ وdaysAtLevel). قيمة kind إمّا no_progress_at_level (آخر 3 أيام تدريب منتهية في المستوى، في كلّ منها 3 إجابات محسوبة على الأقل، كلّها دون 60 %) وإمّا support_review_suggested (21 يومًا في المستوى 1 مع 3 أيام تدريب على الأقل، اقتراح فقط). يُغلق التنبيه حين يتغيّر المستوى. النطاق المجهول أو التابع لمؤسسة أخرى 404؛ والصفّ الذي لا تدرّسه المعلّمة أو المجموعة التي لا تملكها 403 NOT_CLASS_TEACHER.
  • الاطّلاع. يعيد POST /api/training/alerts/{alertId}/acknowledge القيمة { alertId, acknowledgedAt } ويسجّل من اطّلع على التنبيه، مرّة واحدة. لا يغيّر شيئًا آخر: يبقى التنبيه مفتوحًا، ويبقى المستوى، ولا يُكتب حدث إتقان. 409 مع reason بقيمة already_resolved (تُفحص أوّلًا) أو already_acknowledged؛ و403 حين لم تعد المعلّمة تصل إلى الطالب؛ و404 للتنبيه المجهول أو التابع لمؤسسة أخرى.
  • مستوى التدريب في التقرير. يضيف MeasureResult.trainingLevel (في perSkillStatus[].measure وdiagnostic[].measure وmeasures في تفاصيل الجلسة) الحقل source: training هو مستوى الطالب المحفوظ الآن لتلك المهارة الحاملة في العام الدراسي للصفّ، وscreen هو المستوى الذي يبدأ منه التدريب حسب التقييم حين لم يبدأ التدريب بعد.
  • الإشعارات. نوعان جديدان، training_no_progress وtraining_support_review_suggested (action_required، لمعلّمات صفّ الطالب، ويُحفظان 30 يومًا)، مع sourceEntityType بقيمة training_progress_alert ومعرّف التنبيه في sourceEntityId. تحمل الحمولة studentId (معرّف مستخدم الطالب نصًّا رقميًا، وكذلك الآن في skill_alert_assigned وstudent_alert_assigned) وclassId وstudentName وalertId وskillId وskillLabelAr وlevelNumber وlevelNameAr، وdaysAtLevel في اقتراح المراجعة. عمليات قائمة الإشعارات كما هي.
  • التدريب. يحصل السؤال الذي يُعرض مرّة أخرى على محاولتيه الخاصّتين (قاعدة المحاولتين لكل عرض، لا لكل قائمة). وتأتي قطوع المستويات القديمة (band) من صفّ practice_band_routing بالقيم نفسها، ولم تعد قائمة التدريب القديمة تعرض أسئلة نماذج التقييم ولا أسئلة الجسور.
  • تطبيق الويب. تعرض صفحة الطالب بطاقة «مستويات التدريب»، وتعرض صفحة التنبيهات «تنبيهات التدريب» مع «اطّلعت»، ويفتح نوعا الإشعار مستويات تدريب الطالب، ويقول سطر المقياس هل مستوى التدريب «حسب التدريب الحالي» أم «حسب نتيجة التقييم». انظر استخدام المنصّة: المعلّم.

قوائم الكلمات الموقوتة ومستوى القراءة الجهرية في الصفّ الثاني، 2026-10-01

عملية جديدة واحدة؛ تتغيّر أربع (الجديدة GET /api/word-lists/{id}/sheet.pdf؛ وتتغيّر GET /api/word-lists وPOST /api/word-lists/assessments وPOST /api/orf/assessments/{id}/stop وGET /api/orf/assessments/{id}؛ أُعيد توليد openapi:check، 390 مسارًا). الترحيلان 20261001400000 (تعبئة بيانات لمرّة واحدة) و20261001410000. النشر: نفّذ الترحيلين، ثمّ config:publish، ثمّ حوّل الحركة، ثمّ seed-main (توقيت القوائم يأتي من البذرة وحدها؛ وحتى تنفيذها تبقى القوائم غير موقوتة ولا يتعطّل شيء)، ثمّ أعد تنفيذ عبارات التعبئة مرّة أخرى للجلسات التي أُنهيت أثناء التحويل.

  • قوائم موقوتة. تُقرأ قائمة الكلمات للمدّة التي يسمّيها إعدادها (60 ثانية للقائمتين حاليًا). للقائمة الموقوتة يأخذ POST /api/word-lists/assessments الحقل last_word_index (يبدأ من 0، آخر كلمة وصل إليها الطالب) والحقل elapsed_seconds (من 1 حتى المدّة)؛ والقائمة غير الموقوتة ترفض last_word_index. الكلمات المحاوَلة هي آخر كلمة زائد واحد، وتُهمل العلامات بعدها، والكلمات الصحيحة في الدقيقة تُحسب على الثواني الفعلية، فالطالب الذي ينهي مبكرًا يُقاس على الزمن الذي قرأ فيه.
  • الاستجابة. تضيف timed وerrors وwcpm وlastWordIndex وelapsedSeconds وaccuracyBand وrateBand وbandBasis (accuracy أو rate أو lower_of) وprovisional. صار band قابلًا لأن يكون null: تُصنَّف الدقّة والسرعة كلّ منهما وفق جدول قطع القراءة الجهرية، ويحدّد الأساس المُعَدّ قيمة band الواحدة، والقطع الفارغ يسجّل القراءة بلا مستوى (projection.skippedReason: not_banded؛ ولا يدخل شيء في صورة المهارات). لا يُرجع إلى الحدود المُعَدّة إلا حين يغيب صفّ الدقّة كلّه.
  • الرفض (422، ولا يُكتب شيء): word_list_timing_required وword_list_elapsed_exceeds_duration وword_list_last_word_out_of_range وword_list_not_timed وword_list_grade_mismatch، والجديد word_list_window_mismatch (القائمة تخصّ نافذة تقييم واحدة والقراءة ستُحفظ تحت نافذة أخرى).
  • اختيار القائمة. يأخذ GET /api/word-lists الحقل studentId فيعيد قوائم نافذة هذا الطالب وحدها (قوائم تلك النافذة أوّلًا، ثمّ القوائم الصالحة لكلّ النوافذ)؛ و404 أو 403 حين يكون الطالب خارج النطاق. تضيف كلّ قائمة timing (timed وdurationSeconds) وwordsPerRow (5 حين لا تسمّي القائمة عددًا) وassessmentWindow.
  • ورقة الطالب. يعيد GET /api/word-lists/{id}/sheet.pdf ورقة A4 التي يقرأ منها الطالب: الكلمات في صفوف شبكة التصحيح نفسها، من اليمين إلى اليسار، بلا أرقام. اسم الملف ASCII في filename وعربي في filename*. والنصّ المطبوع الذي لا يجتاز مرشّح اللغة يُجاب بـ 422 مع reason: language_safety_blocked.
  • لماذا ينطبق مستوى القراءة الجهرية. يضيف POST /api/orf/assessments/{id}/stop الحقل rateCut (applied أو withheld_in_window أو no_norm، ولا يغيب أبدًا) والحقل provisional. تعني withheld_in_window أنّ النافذة تسجّل السرعة بلا قطع، وأنّ المستوى هو مستوى الدقّة (projection.accuracyBand)؛ وهذا اليوم هو الصفّ الثاني في بداية العام ومنتصفه. ويضيف GET /api/orf/assessments/{id} الحقل rateCut (null حتى الإنهاء) وaccuracyBand وprovisional. الثلاثة هي ما سجّله الإنهاء، فلا يغيّر أيّ تعديل لاحق في الإعدادات وصف جلسة قديمة.
  • ملخّصات الطلاقة تحتسب الجلسات الفورية. صار الإنهاء يكتب صفَّي cbm_scores تحت النافذة التي حدّدها البدء، مع الصفّ الذي حُدّد له القطع، فتحتسبهما ملخّصات الطلاقة للمدرسة وللصفّ التي تقرأ حسب النافذة. ويملأ ترحيل التعبئة نافذة الصفوف السابقة من الأدلّة التي سجّلها الإنهاء نفسه. والجلسة غير المرتبطة بمهارة تسجّل قراءتها على الجلسة وحدها ولا تكتب صفًّا في cbm_scores (كان إنهاؤها يفشل).

مجال فيه مهارة ضعيفة واحدة بين مهارات مقيسة قليلة، 2026-10-01

لا عمليات جديدة؛ أشكال الاستجابة كما هي. صفوف القاعدة تأتي من البذرة وحدها: نفّذ seed-main ثمّ config:publish بعد النشر.

  • مجال التقييم الذي قيست فيه مهارات قليلة (أربع على الأكثر) وثبت ضعف واحدة منها فقط صار يُقرأ isolated_skill_need عبر القاعدة المؤقّتة DDR-PRV-01 (الحدّ DTH-PRV-01)، حيث لم تنطبق قبلها أيّ قاعدة من قواعد الشريكة فبقي المجال بلا حالة. وثغرة القواعد في مجال واحد صارت تؤجّل ذلك المجال وحده، لا الجلسة كلّها. تبقى القاعدة مؤقّتة حتى تجيب الشريكة عن Q-SSE-DDR-SOLE-1.

التقييم بالمقاييس: نموذج واحد ومستوى لكل مقياس، 2026-10-01

لا عمليات جديدة؛ تتغيّر إحدى عشرة (عمليات /api/admin/diagnostic-blueprint الأربع، وPOST /api/diagnostic-sessions/start وPOST /api/diagnostic-sessions/start/re-diagnostic وGET /api/reports/students/{id}/sub-skill-report وGET /api/reports/students/{id}/session-results وGET /api/reports/students/{id}/sessions/{kind}/{sessionId} وGET /api/parent/children/{childId}/growth وPOST /api/admin/delivery/dry-run-replay؛ أُعيد توليد openapi:check). الترحيلات 20261001210000 و20261001211000 و20261001220000. النشر: شغّل الترحيلات، ثم seed-main (جداول الدرجات وقواعد المستويات وأربع قواعد لغوية تأتي من البذرة فقط) وconfig:publish.

  • خلايا المقاييس. يقبل PUT /api/admin/diagnostic-blueprint/{grade}/{cycle} الحقل measures (رموز مقاييس التقييم بترتيب العرض) بدل subSkillIds؛ أرسل واحدًا منهما فقط. تُشتقّ subSkillIds للخليّة من المهارات الحاملة للمقاييس. أسباب 422: duplicate_measure وmeasure_not_in_grade وno_digital_measure وcarrier_conflict وcatalog_gap. الخليّة التي لا يخدم مقاييسها أي نموذج تقييم معتمد تُنشر مع measureWarnings (no_operational_form)، أو تُرفض 422 no_operational_form مع strict: true. والمقياس الذي يُصحَّح بجدول مؤقّت يحتاج acknowledgeProvisional: true (وإلا 422 provisional_scoring_table)، ويُرفض على المستوى العام 422 provisional_not_publishable_globally. تحمل الخلايا measures (فارغ لخليّة المهارات) وprovisional؛ ويضيف GET الحقلين measureOptions وforms؛ وتحمل صفوف السجلّ measures.
  • الجلسة. جلسة خليّة المقاييس تعرض نموذج تقييم واحدًا بترتيبه، بحدّ الوقت الخاص بالصف، وفي الصفين الثالث والرابع breakBefore: true بعد آخر سؤال على القطعة (ويبقيها /state و/resume حتى الإجابة التالية). إن لم يوجد نموذج معتمد: firstItemId: null مع reason: no_screening_form. وبداية إعادة التقييم تعيد reason نفسه، وفي نافذة المقاييس تعيد الخليّة كلّها.
  • جسم إعادة التقييم. لم يعد POST /api/diagnostic-sessions/start/re-diagnostic يشترط subSkillIds. نافذة المقاييس تتجاهل الحقل وتعيد الخليّة كلّها، ونافذة المهارات من دونه تردّ 422 sub_skills_required.
  • التقارير. مخطّط جديد MeasureResult (labelAr وraw وmax وcomplete وincompleteReason مع incompleteReasonAr وlevel وtrainingLevel وprovisional وsessionId). يحمله perSkillStatus[].measure في تقرير الطالب وdiagnostic[].measure في نتائج الجلسات على صف المهارة الحاملة للمقياس (فارغ على صف المهارة). وتضيف بطاقة READ_COMP الحقل composite (MeasureComposite، درجة الفهم من 12 للاطّلاع فقط، لا تدخل أي تجميع). وتضيف تفاصيل الجلسة measures، لكلّ منها items (MeasureItemReview: الترتيب والنمط والمهارة وصحّ أو خطأ وإجابة الطفل)، دون نص السؤال ولا الإجابة الصحيحة أبدًا.
  • الأهل. يضيف GET /api/parent/children/{childId}/growth الحقل measures: [{ labelAr, statusLabel }] (ParentMeasureDTO): المقاييس المكتملة من آخر تقييم، لكلّ منها إحدى أربع عبارات، بلا أرقام ولا رموز. ويطبع ملف PDF للأهل الأسطر نفسها.
  • الإعادة التجريبية. يقبل POST /api/admin/delivery/dry-run-replay الحقلين pinnedItemBankId وformServe لإعادة عرض سؤال من نموذج تقييم.

استيراد محتوى الشريكة، 2026-10-01

لا عمليات جديدة؛ تتغيّر سبع (POST /api/items/import وGET /api/items/import وGET /api/items/import/{batchId} وPOST /api/items/import/{batchId}/approve وGET /api/items وGET /api/items/{id} وPOST /api/orf/assessments/{id}/stop؛ أُعيد توليد openapi:check). الترحيلات من 20261001200000 إلى 20261001200800. النشر: شغّل الترحيلات، ثم seed-main (صفوف الإعداد الجديدة تأتي من البذرة فقط) وconfig:publish.

  • contentKind عند الاستيراد. يقبل POST /api/items/import الحقل contentKind: item (الافتراضي)؛ وcontent_bundle، دفعة تدريب أو جسر { passages, items } تمرّ ببوابة القطع ثم ببوابة الأسئلة (ويضيف الردّ passageImportBatchId وpassageCounts)؛ وscreening_form، نموذج واحد يُستورد وحدةً واحدة (صفّ مرفوض يرفض النموذج كلّه ولا يُحفظ شيء، والردّ 200 مع formRejected: true؛ ويضيف الردّ screeningFormId)؛ وscaffold_prompt؛ وword_list. الحقل sourceDeclared مطلوب للأنواع التي تحمل أسئلة فقط (422 بدونه).
  • التقارير. يعرض GET /api/items/import/{batchId} دفعات الأسئلة ونماذج التقييم ومكتبة التلميحات وقوائم الكلمات (لا دفعات القطع أبدًا): contentKind، وsourceDeclared (فارغ للتلميحات والقوائم)، وعلى كل صف passageId وwordListId وscaffoldPromptId بجانب itemBankId. ويضمّ rejectReason أسباب العقود (form_item_count_mismatch وmeasure_not_in_grade وform_rejected وأسباب prompt_* الثلاثة وword_list_* الخمسة، والباقي في المخطط). ويصفّي GET /api/items/import بحسب contentKind (الافتراضي item).
  • الاعتماد. يُعتمد نموذج التقييم وحدةً واحدة: exceptions يعيد 422 مع form_is_one_unit، وتُرقّى معه الأسئلة التي بلا تقدير صعوبة، وتُسحب النسخة الحيّة السابقة لـform_id نفسه. وتسحب قوائم الكلمات والتلميحات النسخة الحيّة السابقة لـlist_id أو prompt_id. ويضيف الردّ retired.
  • صفوف الأسئلة. الصف الذي فيه content_role (screening أو target_training أو bridge_practice) يحمل measure_code وitem_pattern وform_id وform_position وtraining_level وbridge_target_skill_id، وتُفحص مقابل صفوف الإعداد المنشورة؛ وتحدّد المنصّة content_purpose. أسئلة التقييم لا تُقدَّم إلا داخل نموذجها، وأسئلة الجسر لا تُقدَّم إلا في خطوة الجسر، ولم تُفعَّل هذه الخطوة بعد.
  • الإقرار والحجم. الاستيراد الذي يحمل أسئلة (item وcontent_bundle وscreening_form) يحتاج agreementSignoff (من راجع التطابق العربي خارج المنصّة ومتى؛ ويُحفظ في تقرير الدفعة). بدونه يكون الردّ 422 مع agreement_signoff_required، ولا يُحفظ شيء. وحجم الملف بعد فكّ الترميز محدود لكل نوع (item وcontent_bundle عشرة ميغابايت، وscreening_form اثنان، وscaffold_prompt وword_list واحد)، وإلا فالردّ 413.
  • النماذج. ردّ كل نموذج يحمل formProblems (missingPositions وduplicatePositions وcountMismatch وmeasuresNotInGrade). والنموذج الذي ينقصه مقياس كامل يُرفض، ويسمّي countMismatch المقياس مع got: 0.
  • النطاق والنسخ. form_id وlist_id وprompt_id فريدة لكل مؤسسة (والفارغ مشترك)، فاعتماد نسخة مؤسسة لا يسحب النسخة المشتركة أبدًا. واعتماد نسخة أقدم بينما نسخة أحدث حيّة يعيد 409 مع newer_version_operational. والملف نفسه من مؤسسة أخرى استيرادٌ خاص بها، لا إعادة للاستيراد السابق.
  • عرض التأليف. يضيف GET /api/items وGET /api/items/{id} مع view=authoring الحقلين contentRole وscreeningFormId. ونسخ سؤال تقييم يعيد 422 (form_item_not_duplicable)؛ وPATCH يُخرج سؤال تدريب أو جسر عن عقده يعيد 422 مع سبب العقد.
  • دقّة القراءة الجهرية. يُطبَّق صفّ المعيار الأخصّ. الصفّ الفارغ يسجّل الدقّة دون مستوى (accuracyBand: null عند الإيقاف)، ويكون skippedReason هو not_banded حين لا يكون للسرعة مستوى أيضًا. ولا يُرجع إلى الحدّين 95 و90 إلا حين لا يوجد صفّ مطابق.

الواجهة ترسل التدريب، 2026-10-01

لا عمليات جديدة. هذا عميل الواجهة لعمليات «تدريب» في القيد التالي.

  • من أين يبدأ الإرسال. صفحة الجلسات («+ جلسة جديدة» ← «تدريب اليوم»، ثم الصفّ كلّه أو مجموعة دعم أو طلاب تختارهم)، ولوحة الصفّ، ورأس مجموعة الدعم، وصفحة الطالب («تعيين التدريب» عبر assign-training). ويرسل فريق أمل من /admin/training ومعه دائمًا onBehalfOfTeacherUserId (معلّمة الصفّ من GET /api/classes/{classId}/teachers، أو صاحبة المجموعة).
  • مفتاح منع التكرار واحد لكل جسم طلب. في الفتح الواحد للنافذة تحتفظ الواجهة بمفتاح X-Idempotency-Key واحد لكل جسم مختلف ترسله. إرسال الجسم نفسه مرّة أخرى (إعادة محاولة بعد انقطاع، أو «إعادة الإرسال» لطالب نتيجته failed) يستعمل المفتاح نفسه، فيُعيد الخادم الإرسال الأصلي بدل الفتح مرّتين. والجسم المتغيّر (وقت آخر، أو هدف آخر، أو معلّمة أخرى) يأخذ مفتاحًا جديدًا. ويتّبع assign-training القاعدة نفسها، ويُعاد إرسال ردّه 503 ذي reason: failed بالمفتاح نفسه.
  • الأخطاء التي تسمّيها الواجهة. 422 window_already_over / window_too_short / until_time_required / on_behalf_required / on_behalf_not_a_teacher، و409 empty_target، و403 on_behalf_teacher_not_in_scope. ويعرض 422 idempotency_key_reused سطر إعادة المحاولة الهادئ ويترك ذلك المفتاح، فتحمل المحاولة التالية مفتاحًا جديدًا. ويقول 429 RATE_LIMITED متى تُعاد المحاولة، من Retry-After (بالدقائق الكاملة، ودقيقة حين يغيب الرأس أو لا يُكشف)، بلا عدّ تنازلي. وأيّ خطأ آخر، ومنه 503 TRAINING_UNAVAILABLE (training_window_catalog_unavailable، أو failed في assign-training)، سطر هادئ واحد لإعادة المحاولة. والطالب الذي نتيجته send_closed (أو ردّ assign-training بـ409 send_closed) نهائي: لا «إعادة الإرسال»، وحين يكون send_closed سبب كل من لم يُفتح لهم تعرض النتيجة إرسالًا جديدًا بمفتاح جديد. وعند الإنهاء المبكر يكتفي 409 already_closed و409 nothing_open بتحديث القائمة.
  • صفوف صفحة الجلسات وقائمة الطلاب. صفّ التدريب ذو subtype: "personal" يفتح /teacher/sessions/training/{dispatchId} (وقد يحمل classId: ""؛ تعرض الشارة classNameAr، أو supportGroupNameAr لإرسال إلى مجموعة). يُعرض كل وقت إغلاق بصيغة HH:MM بالمنطقة الزمنية timeZone التي يحملها ردّه (Asia/Hebron لمدرسة في فلسطين، وAsia/Amman لغيرها)، ويُحسب الوقت التقديري في خطوة التأكيد بـtimeZone الذي يُعيده GET /api/training/window-options. وتُعرِّف القائمةُ outcome بإحدى النتائج السبع المخزّنة أو null، ولا تكون failed أبدًا.
  • خطوة الوقت وسطر التأكيد. بساعة المدرسة (timeZone في خيارات الوقت) يُعطَّل خيار نهاية الدوام حين يمضي schoolDayEndsAt أو يبقى أقلّ من minMinutes، مع سببه، ويُختار الدرس بدل الافتراضي المعطَّل. ويقول سطر التأكيد إنّ التدريب سيُرسل («سيُرسل التدريب إلى N طالبًا حتى HH:MM.»)، لا إنّه سيُفتح لكل طالب؛ والنتيجة تذكر العدد الحقيقي.
  • صفحة الجلسات. الإرسال الذي لم يفتح التدريب لأيّ طالب ليس سطرًا في القائمة (قاعدة الخادم)؛ وتعرض الواجهة نتيجته من ردّ الإرسال أو التعيين الذي لديها.
  • جهة الطالب. لا تستدعي صفحة التدريب مسار الإنشاء المحذوف أبدًا: تبدأ بـGET …/current/state، وتعرض «لا يوجد تدريب الآن» (مع زرّ «الرئيسية» للعودة) عند 404 training_not_open، وتُنهي اليوم بهدوء عند 409 training_closed أو windowClosed: true. وعند إعادة تحميل الصفحة يُقدَّم السؤال الذي يسمّيه inFlightItemId من جديد، وإعادة التحميل بعد windowClosed: true تنتهي عند شاشة النهاية. والإجابة المحفوظة على الجهاز دون اتصال التي يرفضها الخادم لاحقًا بـ409 training_closed تُحذف من الجهاز ويُبلَّغ عنها بالحدث offline_queue_event ذي op: refused_window_closed.

التدريب يُفتح فقط حين ترسله المعلّمة، لوقت محدّد — 2026-10-01

أربع عمليات جديدة (GET /api/training/window-options، POST /api/training/dispatches، POST /api/training/dispatches/{dispatchId}/close، GET /api/training/dispatches/{dispatchId}/progress)، وعملية حُذفت (POST /api/practice/queues/seed/{diagnosticSessionId} يُجيب الآن 404)، وتتغيّر عدّة أشكال (أُعيد توليد المواصفة). الترحيلات 20261001100000–20261001100200. النشر: قبل بدء الدوام — شغّل الترحيلات، ثم config:publish فورًا (خيارات الوقت تُقرأ من الإصدار النشط)، ثم النشر (deploy/cloud-run/DEPLOY.md).

  • لا يُفتح تدريب من تلقاء نفسه. ترسل المعلّمة التدريب إلى صفّ أو مجموعة دعم تملكها أو طلاب تختارهم، لوقت: هذه الحصّة، أو اليوم حتى نهاية الدوام، أو حتى وقت تكتبه (POST /api/training/dispatches، مع X-Idempotency-Key اختياريًا). يُبنى تدريب كل طالب من آخر تقييم أنهاه هذا العام الدراسي. تذكر الاستجابة outcome لكل طالب (opened_new_queue، opened_existing_queue، trained_today، no_assessment_yet، no_practiceable_subskills، deeper_assessment_pending، catalog_session_active)، وتكون 201 حتى لو لم يُفتح شيء. إعادة الإرسال بالمفتاح نفسه تُعيد الإرسال الأصلي (200، replayed: true).
  • خيارات الوقت صفوف إعداد. يعرضها GET /api/training/window-options مع اسمها العربي وأرقامها والخيار الافتراضي وما إذا كانت القيمة مؤقّتة. الاختيار الخاطئ 422 مع reason: unknown_window، until_time_required، window_already_over، window_too_short.
  • يُقدَّم التدريب فقط ما دام الوقت مفتوحًا. خارج الوقت يُجيب GET …/current/next-item وGET …/current/state بـ404 مع reason: training_not_open. بعد انتهاء الوقت يمكن الإجابة عن سؤال ظهر قبله خلال مهلة قصيرة: تحمل استجابة الإرسال windowClosed: true ولا سؤال بعده. بعد المهلة يُجيب الإرسال 409 training_closed ولا يُسجَّل شيء. يبقى «كيف كان التدريب؟» مطلوبًا. جلسات المكتبة غير مقيّدة بوقت.
  • حقل حُذف. لم يعد practiceSeedSessionId في GET /api/student/next-action وGET /api/student/today-plan؛ يُعرض التدريب فقط ما دام الوقت مفتوحًا.
  • «تعيين التدريب» (POST /api/practice/students/{studentId}/assign-training) إرسال لطالب واحد: جسم اختياري { windowCode?, untilLocalTime?, onBehalfOfTeacherUserId? }؛ و201 يُعيد { queueId, itemCount, dispatchId, outcome, closesAt }؛ والتعيين الثاني يُكمل التدريب (201، لا 409 queue_already_active)؛ والنتائج الأخرى أسباب 409، ومنها الآن trained_today وcatalog_session_active. ويكسب currentTraining في قراءة أيام التدريب الحقول closesAt وopen وwindowLabelAr والقيمة openedBy: "staff".
  • صفحة الجلسات. يعرض GET /api/teacher/sessions?kind=training الإرسالات أيضًا (subtype: "personal"، والحالة open أو closed)، وصار للمؤشّر ثلاثة أجزاء (المؤشّرات القديمة بجزأين ما زالت تعمل). GET /api/training/dispatches/{dispatchId}/progress هو قائمة الطلاب (حالات وأعداد فقط)، وPOST …/close يُنهي الإرسال مبكرًا للجميع (409 already_closed بعد انتهائه).
  • فريق أمل نيابةً عن المعلّمة. على الفريق (RUN_BACKOFFICE / المشرف العام) تسمية المعلّمة (onBehalfOfTeacherUserId، ويجب أن تكون صاحبة الهدف). كل إرسال من الفريق يكتب حدث تدقيق واحدًا، training_activated_on_behalf.
  • الانتقال. التدريبات التي فُتحت تلقائيًا قبل هذا الإصدار تبقى حتى منتصف الليل التالي بتوقيت المؤسسة، ثم تنتهي. وأوّل إرسال من المعلّمة يفتح التدريب لطالب يُنهي مهلة ذلك الطالب قبل ذلك.
  • بعد المراجعة. خطأ عند طالب واحد لا يُفشل الإرسال كلّه بعد الآن: نتيجته failed (المخطّط TrainingSendRecipientOutcome، مع queue: null، ويُحسب في counts.notOpened؛ ولا تُخزَّن، فتعرض القائمة outcome: null)، وإعادة الإرسال بالمفتاح نفسه تكتبه ما دام الإرسال مفتوحًا. الإرسال الذي انتهى وقته أو أُنهي لا يُفتح من جديد: إعادته بالمفتاح نفسه تُجيب عندئذ send_closed لمثل هذا الطالب (نتيجة في الردّ فقط مثل failed؛ لا تُعِد الإرسال، بل افتح تدريبًا جديدًا)، ويُجيب assign-training بـ409 send_closed. وإنهاء إرسال لم يفتح شيئًا 409 nothing_open. والمفتاح المستعمل لطلب مختلف 422 idempotency_key_reused، في الإرسال وفي assign-training؛ ويقبل assign-training المفتاح X-Idempotency-Key وإعادته 200. كل وقت في التدريب يحمل timeZone المدرسة: خيارات الوقت، وwindow في الإرسال، وdispatch في قائمة الطلاب، وcurrentTraining، وردّ assign-training. ويسمّي GET /api/practice/queues/current/state الحقل inFlightItemId (السؤال المعروض الذي لم يُجب عنه بعد، أو null). ويكسب سطر صفحة الجلسات supportGroupNameAr (وclassNameAr هو "" لإرسال إلى مجموعة)، ويعرض عنوانه الفرعي وقت الإنهاء الفعلي لإرسال أُنهي مبكرًا. وإعداد الأوقات المعطوب 503 TRAINING_UNAVAILABLE مع reason: training_window_catalog_unavailable، وassign-training الذي تعذّرت كتابته 503 TRAINING_UNAVAILABLE مع reason: failed. ولمساري الإرسال حدّ: 429 RATE_LIMITED بعد 6 في الدقيقة، مع الرأس Retry-After.

واجهة المعلّم v3 — «التعليم المتمايز» و«الخطط» وتكليف مجموعة المهارة والتسليم «مختلط» (المرحلة S4)، 2026-09-30

5 عمليات جديدة؛ صار amal-api.yaml يضمّ 402 مسارًا و435 عملية.

  • في wp-tdv3.yaml (الوسم teacher-views): getTeacherDifferentiation (GET /api/teacher/classes/{classId}/differentiation?sort=&domain=)، getTeacherSkillPage (…/differentiation/{subSkillId})، getTeacherSkillGroupDetail (…/differentiation/{subSkillId}/groups/{groupKey})، listTeacherPlans (GET /api/teacher/plans?classId=).
  • في wp-sbc-be.yaml: deliverSessionMixed (POST /api/sessions/{id}/deliver-mixed).

تغيّر:

  • يقبل POST /api/sessions/from-blueprint الحقول الاختيارية assignmentContext { subSkillId, groupKeys? } وtargetStudentIds وmediumByStudent، وصار جسمه صارمًا (مفتاح غير معروف ← 422).
  • يُجاب الجسم الجديد بـdeliveryPlan وtargetedCount وdeduplicated، والجسم الذي لا يحمل الحقول الجديدة يُجاب كما كان حرفًا بحرف.
  • حدّ إنشاء الجلسات 30 جلسة لكل معلّم في 15 دقيقة (429 RATE_LIMITED مع retryAfter).
  • يضيف POST /api/sessions/{id}/accept الحقلين evidenceWindow وnotEnrolled.
  • صار PATCH /api/sessions/{id}/edit صارمًا، ويرفض حذف المهارة الأساسية من مسودة موجّهة إلى مجموعة (409 anchor_skill_removed).
  • يرفض distribute-online وgenerate-pdfs جلسةً خُطّط لها وسيط آخر (409 delivery_plan_mismatch).
  • أُضيفت القيمة mixed إلى وسائط التسليم.

الترحيلات: 20261002100700_wp_tdv3_delivery_mode_mixed (قيمة التعداد وحدها) و20261002100800_wp_tdv3_session_target (مصفوفات الهدف، وخطة الوسيط، والبصمة، ووسيط كل مستلم، والفترة المحسوبة، مع 4 قيود CHECK وفهرسين). يُعاد تأريخ الاثنين عند الدمج في الفرع الأمّ بعد مزامنته.

  • تكليف المجموعة يستهدف طلاب المجموعات المختارة كما تعرضهم صفحة المهارة، تمامًا. المجموعة التي تغيّرت ترفض الكتابة كلّها (409 group_stale). المستلمون عند القبول هم المستهدفون الذين ما زالوا مسجّلين، والصفر لا يتّسع أبدًا إلى الصف كلّه.
  • النقرة نفسها مرّتين خلال 120 ثانية تعيد الجلسة الأولى (deduplicated: true مع حالتها الفعلية).
  • «مختلط» يثبّت وسيط كل طالب عند القبول، وdeliver-mixed يسلّم الوسيطين في خطوة واحدة، وإعادة المحاولة آمنة.
  • صار توزيع الجلسة يقرأ فترة التقييم الحالية للصف وعامه الدراسي (كان يقرأ بداية العام، وقد يلتقط صفًّا من عام سابق).

واجهة المعلّم v3 — خلفية صفحة «التقييمات» (المرحلة S3)، 2026-09-30

4 عمليات جديدة؛ صار amal-api.yaml يضمّ 397 مسارًا و430 عملية — wp-tdv3.yaml (الوسم teacher-views): getTeacherAssessments (GET /api/teacher/classes/{classId}/assessments?window=)، getTeacherAssessmentComparison (…/assessments/comparison)، getTeacherAssessmentDetails (…/assessments/details?window=&domain=)، exportTeacherAssessmentResults (…/assessments/export?window=، بصيغة text/csv). تغيّر: يضيف GET /api/admin/audit-log النوع student_data_access (صفوف student_data_access_log — اطلاع المعلّمين والمديرين والمشرفين والمسؤولين على بيانات أطفال بأسمائهم وتصديرها، D-R12)، والرابط المباشر access:<id>، وثلاثة حقول تقبل القيمة الفارغة actorPersona وsubjectStudentCount وtargetClassId، وسقفًا لـoffset قدره 2000 (422 فوقه)؛ ويعرض GET /api/admin/activity الصفوف نفسها في عرض الأمان بالمصدر access مع classId.

  • كل رقم يخصّ فترة واحدة من هذا العام الدراسي؛ لا رقم يجمع بين فترتين؛ والمقارنة من حالة إلى حالة (أعداد الانتقال)، ولا متوسط أبدًا.
  • كل نسبة حصة من الطلاب المقيَّمين مع أعدادها؛ تحمل R7–R9 الحقل dataSufficiency وتُظهر الواجهة الأعداد وحدها ما دام غير كافٍ (D-R11).
  • التصدير بكلمات الحالة فقط، ويُكتب بعد صفّ export_csv في سجل الاطلاع (500 عند تعذّره)، بحدّ 20 تصديرًا لكل معلّم في 15 دقيقة (429)، وبسقف exportMaxRows (422، دون اقتطاع أبدًا)، ويُرفض بـ503 دون محتوى إن لم تكن قواعد اللغة مفعّلة.
  • يظهر الفحص الأعمق approved_not_started حتى أول إجابة في جلسته، ثم in_progress (D-R14).

تجربة المعلّم v3 — حساب معلّم الدعم (S15)، 2026-09-30

لا عمليات جديدة (عدد مسارات amal-api.yaml وعملياته لم يتغيّر). ترحيل واحد: 20261002100600_wp_tdv3_learning_support_flag (teacher_profile.learningSupport، القيمة الافتراضية false).

  • يضيف GET /api/auth/me الحقل learningSupport (للمعلّم: قيمة منطقية؛ لكلّ دور آخر: null) والحقل lastTeacherClassId (الصفّ المخزَّن عبر PUT /api/users/me/last-class ما دام المعلّم مسندًا إليه، وإلّا null).
  • يضيف GET /api/users/{id} (للمعلّم) الحقل profile.learningSupport؛ ويقبل PATCH /api/users/{id} الحقل teacher.learningSupport (قيمة منطقية؛ لمسؤول المؤسّسة وحده). يسجّل سطر التدقيق تعديلًا على ملفّ المعلّم (fields: ["teacher"])، دون اسم الإعداد ودون قيمته. للعرض فقط: لا يقرؤه نطاق وصول أيّ مسار ولا صلاحياته. ثبت ذلك بطريقتين: مجموعة اختبارات تقلب الحقل (معطّل ← مفعّل ← معطّل) على كلّ قراءة في الشريحتين اللتين يستخدمهما المعلّم اليوم (wp-tdv3، wp-support-groups) فتجد الحالة والمحتوى متطابقين؛ ويحرس كلَّ مسار آخر فحصٌ للمصدر لا يسمح بالحقل إلّا في خمسة ملفّات (ليس بينها مساعد نطاق أو صلاحيات).

واجهة المعلّم v3 — الأساس الخلفي (المرحلة S2)، 2026-09-29

7 عمليات جديدة؛ صار amal-api.yaml يضمّ 393 مسارًا و426 عملية — wp-tdv3.yaml (الوسم teacher-views): getTeacherClasses، getTeacherClassHome، getTeacherClassNeeds، listTeacherNeeds، listTeacherStudents؛ وputMyLastClass (PUT /api/users/me/last-class) وputMyTeacherGender (PUT /api/users/me/teacher-gender)، كلاهما في wp-a3.yaml. تغييرات: يضيف GET /api/auth/me الحقول features.teacherV3 وteacherGender وtimeZone؛ ويقبل PATCH /api/users/{id} الحقل teacher.gender وتعرضه تفاصيل المستخدم للمسؤول؛ ويردّ POST /api/alerts/{id}/acknowledge و/dismiss بـ409 حين لا يعود التنبيه مفتوحًا. الترحيلات 20261002100000_wp_tdv3_last_teacher_class (عمود اختياري user_preferences.lastTeacherClassId)، 20261002100100_bundle_recommendation_current_idx، 20261002100200_wp_tdv3_target_sub_skill، 20261002100300_wp_tdv3_cbm_alert_open_series (شغّلوا فحص القراءة المسبق في deploy/cloud-run/DEPLOY.md أولًا) و20261002100400_wp_tdv3_cbm_alert_trend_signal_at و20261002100500_wp_tdv3_teacher_gender (عمود اختياري teacher_profile.gender) — كلها بعد 20260929050000_p3c5_snake_case_tables في main، وهو مطبَّق في الإنتاج.

  • للمعلّم فقط؛ الرفض 403 من بوابة الصلاحيات وحدها، و404 لكل ما هو خارج النطاق. مفتاح الواجهة الجديدة (TEACHER_V3_ORGS) يغيّر العرض وحده — كل مسارات /api/teacher/* تجيب بالشيء نفسه والمفتاح مفعّل أو معطّل.
  • كل نسبة محسوبة من الطلاب المقيَّمين؛ «لم يُقيَّم بعد» و«قيد المراجعة» أعداد لا تدخل في المقام.
  • كل قراءة تسمّي طفلًا وصلت إليه المعلّمة عبر مجموعة دعم فقط تكتب سطرًا واحدًا في سجلّ الوصول، وإن تعذّرت كتابته لا تُرسَل القراءة.
  • قراءات الاحتياجات تقبل عائلة واحدة أو قائمة عائلات مفصولة بفواصل، ومؤشّر صفحات مربوطًا بتلك القائمة، وreach=group في R3b (طلاب مجموعات الدعم الخاصة بالمعلّمة). يحمل كل صف subSkillId وsubSkillNameAr وheldForImplementation، وبحسب النوع cbm {alertType, severity} أو planId أو activation.
  • إصلاح: الإقرار أو التأجيل المتأخر كان يعيد كتابة تنبيه مغلق أو مؤجّل. صار الانتقالان لا يعملان إلا على تنبيه مفتوح؛ وإلا فـ409 ولا يُكتب شيء ولا يُسجَّل إجراء للمعلّمة.
  • إصلاح: تنبيه قياس واحد لكل سلسلة قياس. صار تنبيه القياس المفتوح يسمّي المهارة التي قيست، فلا تمحو سلسلة ثانية للطفل نفسه الأولى؛ ويقرأ نظام الاستجابة للتدخّل آخر إشارة كتبها مُصدِر التنبيه (trendSignalAt) لا آخر تحديث للصف.
  • صيغة مخاطبة المعلّم (FEMALE / MALE / دون تحديد — وتُستخدم صيغة المذكّر): يحدّدها المعلّم (PUT /api/users/me/teacher-gender، لنفسه فقط، دون سطر تدقيق) أو مسؤول النظام في مؤسسته (PATCH /api/users/{id}، ويسجّل سطر التدقيق تعديلًا على ملفّ المعلّم fields: ["teacher"] دون اسم الإعداد ودون قيمته)؛ لا تُعاد إلا في /me الخاص بالمستخدم وفي تفاصيل المستخدم للمسؤول، ولا تظهر في أي قائمة، ولا يقرأها أي قرار. و/me.timeZone مشتقّة من دولة المؤسسة (الأردن Asia/Amman، فلسطين Asia/Hebron).
  • يُختم عند التفعيل هدفُ الخطة من المهارات الفرعية (bundle_assignment.targetSubSkillId). ويقبل استقبال النشاط alert_action.surface = "needs" (كان يرفضه، والحدث المرفوض يُسقط دفعته كلها).

بطاقة المساعدة المختصرة بصيغة مخاطبة المعلّم — 2026-09-27

لا عمليات جديدة. مُعامل استعلام اختياري واحد على عملية موجودة (WP-TDV3 S6c؛ الشريحة wp-onb-be.yaml).

  • GET /api/teacher/help/cheat-sheet.pdf?form=f|m. المُعامل form اختياري ومغلق: f أو m، وأيّ قيمة أخرى تُرجع 422. من دونه يبقى ملف PDF مطابقًا بايتًا ببايت لما كان يُقدَّم من قبل، فلا يتغيّر أيّ مستدعٍ حاليّ. ومعه تُكتب الأسطر التسعة التي تخاطب المعلّم أو تسمّيه (ستّة أسطر بضمير المخاطَب، وعنوان رمز التجاوز «تعديل المعلّم/المعلّمة للحزمة (خروج)»، وعنوانا الصفحتين «دليل التهيئة السريع للمعلّم/للمعلّمة …») بتلك الصيغة. ولم تتغيّر البوابة (معلّم) ولا النطاق ولا الحدث cheat_sheet_downloaded.
  • نصوص الخادم الموجّهة إلى المعلّم لم تتغيّر. رسائل المساعدة والمتابعة وسير العمل والاستجابة للتدخّل تحتفظ بأشكال استجاباتها، وتبقى مكتوبة بصيغة المؤنّث؛ والواجهة تعرضها بصيغة القارئ.

نصوص القراءة الجهرية، وسطر طريقة القراءة، واستيراد محتوى أدقّ — 2026-09-29

لا عمليات جديدة. حقول جديدة ومعامل استعلام واحد جديد (أُعيد توليد openapi:check). الترحيلان 20261001600000_ci_enum_values و20261001600100_ci_oral_text_reading_convention. النشر: شغّل الترحيلين؛ لا حاجة إلى seed ولا إلى config:publish.

  • GET /api/passages: كل صفّ يحمل purpose (comprehension | oral_text)، وتقبل القائمة معاملًا اختياريًا ?purpose=. المرشِّح يضيّق النطاق المعتاد للمستدعي فقط (النصوص العامة ونصوص مؤسسته) ولا يوسّعه أبدًا. نص القراءة الجهرية يُقرأ ويُصحَّح ولا يُسأل عنه: ربطه بسؤال يُجيب 422 unknown_passage.
  • readingNoteAr (نص أو null): السطر العربي الواحد الذي يقول للمعلّمة كيف يُقرأ آخر الكلمات، في GET /api/orf/passages وPOST /api/orf/assessments/start وPOST /api/reading-assessments/planned/{id}/start وGET /api/word-lists. يكون null حين لا يحدّد المحتوى طريقة قراءة. وللصفّ الذي له نصوص قراءة جهرية لا يعرض GET /api/orf/passages غيرها.
  • بوابة الاستيراد (أمر على الخادم content:import، وليس مسار API): نص القراءة الجهرية (content:import oral-texts) الذي يخالف قواعده يُرفض بالسبب oral_text_invalid مع اسم الحقل؛ ونوع النص textType حصرًا narrative أو informational؛ والكلمة غير الحقيقية المستعملة في قائمة صفّ آخر word_list_duplicate؛ والحرف الذي عليه شدّة وسكون معًا يُرفض؛ وتكرار metadata.partner_item_id يرفض نموذج التقييم، وإعادة إرسال النموذج تُظهر الفرق سؤالًا سؤالًا؛ و--manifest يقرأ ملف التسليم من الشريك؛ والدفعات التي صاغها الذكاء الاصطناعي أو التجريبية لا تُعتمد من سطر الأوامر أبدًا.
  • الصعوبة المبدئية: إصدار المعادلة الآن v2 (حدّ المتطلّب المعرفي يقرأ أسماء عمليات القراءة التي في العقد). القيم المحفوظة لا يُعاد حسابها.
  • العرض: خيارات CHOOSE_CORRECT_SPELLING لا تُقرأ بصوت أبدًا (نصّ السؤال يُقرأ). وتبقى خيارات الاختيار بترتيب مختلف في كل عرض، والتصحيح بمعرّف الخيار.
  • الأدلّة: عقود الشريك في content-pipeline/partner-handoff/ (والجديد 13-oral-texts.md).

اقتراح الفحص الأعمق يتبع تصحيح المعلّمة — 2026-09-27

لا عمليات جديدة. يكسب GET /api/backtrack/students/{studentId} الحقل firedSignals، وتكسب قائمة الحالات القيمة withdrawn (لا تُعيد هذه القراءة اقتراحًا مسحوبًا أبدًا)؛ وصار لجسم ردّ 409 في الموافقة مخطّطه الخاص BacktrackApproveConflict؛ أُعيد توليد المواصفة. الترحيلات من 20261001050000 إلى 20261001050600 (قيود على صفوف جدولَي إعداد، وعبارة سبب لكل قاعدة، والحالة الجديدة، وقواعد الاقتراح الخمس نفسها، ومهلة حجز الموافقة). النشر: شغّل الترحيلات ثم seed-main وconfig:publish. قواعد الاقتراح تصل الآن مع الترحيلات، فيمكن أن يُفتح الفحص قبل تشغيل seed-main؛ وما زال seed-main لازمًا لصفوف سرعة القراءة الجهرية، ويرفض config:publish الكتالوج الذي لا يجتاز الفحوص الجديدة. وفي قاعدة بيانات لم تملأها البذرة بعد، ينتظر فحص رموز مهارات القواعد تشغيل seed-main (بتحذير في السجلّ) بدل الرفض.

  • الاقتراح الذي لم تُجب عنه المعلّمة يتحدّث مع كل تصحيح. قائمة كلمات تُصحَّح بعد القراءة الجهرية تقوّي سببه الآن (يتغيّر reasonCode، مثلًا إلى SEVERE_TEXT_ACCURACY_WITH_DECODING_SIGNAL). وإذا أعادت قراءة لاحقة الدقّة إلى المدى المتوقّع يُسحب الاقتراح: وقبول المسحوب أو رفضه 409. وإذا انخفضت الدقّة مجدّدًا في النافذة نفسها يعود الاقتراح. بعد أن تقبل المعلّمة أو ترفض، لا تغيّره أي قراءة لاحقة.
  • اقتراح هذا العام وحده يؤخّر التدريب ما دام بلا جواب. إرسال «تدريب» و«تعيين التدريب» ينتظران (deeper_assessment_pending) اقتراحًا لم تُجب عنه المعلّمة في هذا العام الدراسي، وفحصًا جلسته مفتوحة، أو قبلته المعلّمة خلال آخر 10 دقائق (ما زالت الموافقة تفتحه)، في أي عام. الاقتراح المسحوب، أو الذي بقي بلا جواب من العام الدراسي الماضي، أو موافقة توقّفت في منتصفها قبل أكثر من 10 دقائق، لا يؤخّر التدريب بعد الآن. والدقائق العشر هي صفّ backtrack في engine_parameters.
  • القراءة تعرض ما يؤخّر التدريب. يُعيد GET /api/backtrack/students/{studentId} أوّلًا الاقتراح الذي يؤخّر تدريب الطالب (ولو كان فحصًا مفتوحًا من عام سابق). وإن لم يوجد، يُعيد أحدث اقتراح في هذا العام الدراسي، أو null إن لم يوجد أو كان مسحوبًا. واقتراح نافذة أحدث يسحب الاقتراح الذي لم يُجَب عنه في نافذة أقدم من العام نفسه.
  • قبول الاقتراح يذكر سبب الرفض. يحمل ردّ 409 من POST /api/backtrack/{id}/approve الحقل reason بقيم محدّدة: not_recommendable، أو recommendation_expired (اقتراح بقي من عام دراسي آخر)، أو approval_in_progress (موافقة أخرى تفتحه الآن)، أو session_already_active، أو rediagnostic_too_soon. يُحجز الاقتراح قبل أن تُفتح جلسته، وتُربط الجلسة به في الخطوة نفسها التي يُؤرشَف فيها تدريب الطالب السابق. فإن تعذّر فتح الجلسة، أو فُتحت بلا أسئلة تُعرض (noEligibleItem: true)، أو فشلت في الطريق، يبقى الاقتراح recommended ولا يبقى شيء مفتوحًا ويبقى تدريب الطالب. وإن وصل رفض في اللحظة نفسها تُغلق الجلسة التي فُتحت للتوّ. وموافقة توقّفت في منتصفها يمكن تكرارها بعد 10 دقائق، ويمكن رفض اقتراح في حالة approved.
  • السبب يذكر كل الإشارات. يجمع reasonAr الآن عبارة الدقّة مع عبارة لكل إشارة ظهرت من قوائم الكلمات أو الفهم (كان يذكر واحدة)، وعبارة الفهم لم تعد توحي بسبب. ويسرد الحقل الجديد firedSignals كل قاعدة ظهرت: { ruleId, kind: opens | strengthens, signal, clauseAr, provisional }، والقاعدة التي فتحت الفحص أوّلًا. وقيمة provisional هي المسجّلة لحظة الاقتراح. الاقتراحات السابقة لتحديث الفحص الأعمق تبقى على سطرها القديم وقائمة فارغة.
  • إعداد أكثر أمانًا. ترفض قاعدة البيانات قاعدة اقتراح تنقصها الحقول التي يحتاجها مصدرها، أو قائمة مطابقة فارغة، أو عبارة فارغة، أو مستوى بدء تدريب أقلّ من 1، أو قاعدة سرعة جهرية صفّها ليس من G1 إلى G6، أو قاعدتَي سرعة جهرية عامّتين للإصدار نفسه. ويرفض config:publish أيضًا قيمة نطاق أو حالة غير معروفة، أو رمز مهارة غير معروف أو غير نشط، أو قيمة measure لا يسجّلها نوع دليل القاعدة (قاعدة قراءة جهرية تقرأ مقياس قائمة الكلمات مثلًا)، أو إصدارين نشطين للقاعدة نفسها.
  • إيقاف الفحص من الإعداد وحده. اجعل كل قاعدة تفتح الفحص غير نشطة وشغّل config:publish: يُنشر الإصدار مع تحذير في السجلّ (config_release.catalog_warning)، ولا يُفتح اقتراح جديد، وتبقى الاقتراحات القائمة كما هي. وتبقى التي لم يُجَب عنها مؤخِّرة للتدريب حتى تُرفض؛ ويسحبها الأمر pnpm --filter server backtrack:withdraw-open --org <id> لمؤسسة واحدة (ويرفض ما دام الفحص يعمل).
  • حقلان في الـDTO. كل اقتراح في ردود القراءة والموافقة وعدم الاعتماد يحمل academicYear (العام الدراسي للصفّ نفسه، مثل "2026-2027") وclaimStale (صحيح فقط لصفّ approved انتهت مدّة حجزه؛ والموافقة عندئذ تحجزه من جديد). ويوثّق عدم الاعتماد أنّه يقبل recommended وapproved.
  • البطاقة في صفحة الطالب (الواجهة). تعرض البطاقة كل ما تُعيده القراءة: اقتراحًا ينتظر القرار، أو صفًّا approved، أو جلسة مفتوحة (من أيّ عام دراسي، فهي ما زالت تؤخّر التدريب)، أو قراءة مكتملة، أو لا شيء (null). تُعرض الموافقة على recommended، وعلى صفّ approved حين تنتهي مدّة حجزه فقط (claimStale)؛ وعدم الاعتماد على recommended وapproved. والصفّ من عام دراسي أسبق من صفّ الطالب الحالي (academicYear) يضيف «فحص أعمق مفتوح من عام دراسي سابق — ينهيه الطالب أوّلًا.». لكل 409 في الموافقة سطر هادئ بحسب reason ثمّ تُقرأ البطاقة من جديد؛ وapproval_in_progress يُقرأ «يجري فتح الفحص الآن — حدّثي الصفحة بعد لحظة.». ومع noEligibleItem: true (لا سؤال يُقدَّم، ومنه مسار كل خطواته تصحّحها المعلّمة) تقول البطاقة «لا توجد أسئلة مناسبة الآن — يبقى الاقتراح قائمًا.» ويبقى زرّ الموافقة.

متى يُقترح الفحص الأعمق للأساسيات — 2026-09-27

لا عمليات جديدة. يتغيّر شكل GET /api/backtrack/students/{studentId} بالإضافة فقط: صار trigger وreasonCode نصّين بدل قائمتين ثابتتين، وصار في readout للفحص المكتمل حقل جديد trainingRecommendation (أُعيد توليد المواصفة). الترحيل 20261001010000 (جدول إعداد عامّ جديد وعمود جديد في إعداد التسلسل). النشر: شغّل الترحيل ثم seed-main وconfig:publish.

  • يُقترح الفحص فقط حين تكون دقّة قراءة الفقرة جهرًا دون المتوقّع بوضوح. القراءة البطيئة الدقيقة، أو ضعف الفهم وحده، أو ضعف قوائم الكلمات وحده، لم تعد تقترح الفحص. صار trigger هو القاعدة التي فتحت الفحص (TEXT_ACCURACY_SEVERE)، وتبقى الاقتراحات الأقدم على A / B.
  • قوائم الكلمات والفهم تشرح السبب. قيمة reasonCode هي SEVERE_TEXT_ACCURACY، أو هي نفسها مع _WITH_DECODING_SIGNAL (قائمة الكلمات غير الحقيقية) أو _WITH_ACCESS_SIGNAL (قائمة الكلمات المشكولة) أو _WITH_COMPREHENSION (ضعف واسع في الفهم). اعرض reasonAr لا الرمز. هذه القواعد صفوف إعداد، فقد تزيد القائمة.
  • الاقتراحات تتبع تصحيح المعلّمة. إنهاء تصحيح قراءة جهرية أو قائمة كلمات يعيد فحص الاقتراح فورًا، ولا يُقترح شيء يعتمد على القراءة الجهرية قبل تصحيحها.
  • بعد الفحص: اقتراح تدريب. الفحص المكتمل الذي حدّد نقطة بدء واضحة يُعيد readout.trainingRecommendation { skillId, skillNameAr, level }: تدريب على تلك المهارة من المستوى الأول، ترسله المعلّمة. لا يبدأ شيء تلقائيًا. قيمته null إذا لم يحدّد الفحص نقطة بدء أو اكتمل قبل هذا التحديث.

سرعة القراءة الجهرية تُقارَن بمعيار نافذة التقييم — 2026-09-27

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (أُعيد توليد المواصفة: وصف حقل واحد). الترحيل 20261001000000 (جدول إعداد عامّ واحد جديد). النشر: شغّل الترحيل ثم seed-main وconfig:publish لتصبح صفوف الإعداد الجديدة سارية.

  • معيار السرعة يتبع نافذة التقييم. صار POST /api/orf/assessments/start يحدّد معيار النافذة التي تُسجَّل فيها القراءة (النافذة المفتوحة للطفل اليوم، وإلا آخر تقييم مكتمل هذا العام الدراسي): بداية العام بمعيار نهاية الصف السابق، ومنتصفه بمعيار مؤقّت بين المعيارين، ونهايته بمعيار الصف نفسه. كانت كل قراءة تُقارَن سابقًا بمعيار نهاية العام. القراءة التي لا نافذة لها تبقى على معيار نهاية العام كما كانت.
  • POST /api/cbm/probes يحدّد معيار assessmentWindow الخاصّ بالقياس، والقياس الذي لا نافذة له لم يتغيّر.
  • حين لا يكون للنافذة معيار سرعة (الصف الثاني في بداية العام ومنتصفه: لا معيار للقراءة الجهرية في الصف السابق)، يُسجَّل المعدّل رقمًا خامًا بلا حكم، وتُقيَّم دقّة القراءة وحدها وفق الإعداد: projection.written قيمته true، وprojection.accuracyBand محدَّد، وprojection.rateBand قيمته null. أيّ صفّ ونافذة يتبعان ذلك صفُّ إعداد لا برمجة، والصف الأول لم يتغيّر. في هاتين النافذتين يُحكم على مجال دقّة القراءة وطلاقتها بالدقّة وحدها، فتبقى صورة القراءة قابلة للتحديد.

متابعات القراءة والمطابقة — 2026-09-26

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (openapi:check سليم). لا ترحيل.

  • المحاولة الأولى الخاطئة في سؤال الترتيب لم تعد تُعيد حكمًا لكل موضع. شاشة الطالب تُعيد كل البطاقات للمحاولة الثانية، فلم تكن هذه الأحكام تُستعمل. ما زالت أسئلة المطابقة وأسئلة الفراغات المتعددة تُعيدها، والكشف بعد المحاولة الثانية لم يتغيّر.
  • إصلاح: الاستراحة بعد النص الطويل كانت تتبع نصّ السؤال الحالي. صارت تقرأ نسخة السؤال المُجاب والسؤال التالي التي عُرضت على الطفل فعلًا، فتعديل السؤال أثناء الجلسة لا يضيف استراحة ولا يحذفها.
  • استوديو الأسئلة: الزوج الفارغ الجديد أو المعنى الإضافي الفارغ يُظهر ملاحظة هادئة («أكمل الصفوف الفارغة أو احذفها.») بدل خطأ أحمر. يبقى الحفظ معطّلًا حتى يُملأ الصف أو يُحذف، ولا تظهر القواعد الحمراء إلا للأخطاء الحقيقية مثل تكرار المعنى.
  • قاعدة مفتاح المطابقة في الاستوديو تُقارَن بقاعدة الخادم. القاعدة في وحدة خادم واحدة بلا اعتماديات، واختبار يشغّل النسختين على الحالات نفسها.

المكافآت تتبع النموّ المقيس فقط — 2026-09-29

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

كل جداول قاعدة البيانات تُسمّى بالأحرف الصغيرة والشرطة السفلية — 2026-09-29

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (openapi:check سليم). الترحيل 20260929050000. النشر: شغّل الترحيل ثم الإطلاق مباشرة دون فاصل، وأي استعلام SQL محفوظ يذكر اسم جدول بالصيغة القديمة بين علامتَي تنصيص يجب تعديله (deploy/cloud-run/DEPLOY.md).

  • أُعيدت تسمية آخر 17 جدولًا كانت ما تزال تحمل أسماءها البرمجية، مثل "User" إلى app_user، و"StudentProfile" إلى student_profile، و"ClassStudent" إلى class_student، و"AuthEventLog" (مع أقسامه الشهرية) إلى auth_event_log. كانت بقية الجداول تتبع هذا الأسلوب أصلًا. أسماء الأعمدة لم تتغيّر.
  • الجدول User صار app_user لا user. كلمة user محجوزة في SQL: الاستعلام SELECT count(*) FROM user دون علامات تنصيص يُعيد صفًّا واحدًا فيه اسم دور قاعدة البيانات بدل أن يفشل.
  • لا تنتقل أي بيانات. إعادة التسمية تغيّر فهرس قاعدة البيانات فقط؛ قورن عدد الصفوف ومحتواها جدولًا جدولًا قبل الترحيل وبعده على قاعدة بيانات فيها بيانات، وجُرِّب على القاعدة بعد التسمية تسجيل الدخول وجلسة تشخيص والمهامّ الليلية.

روابط الدخول ورموزه تُحفظ مُجزَّأة فقط، ومؤشّر واحد لمدير كل مدرسة — 2026-09-29

لا عمليات جديدة. قد تُعيد GET /api/principals/{id} وملف مدير المدرسة في GET /api/users/{id} القيمة schoolId: null (مدير مدرسة حُذف أو مُحيت بياناته لم تعد له مدرسة)؛ ولم يتغيّر أي شكل آخر، وما زالت قائمة المدارس تُعيد principalUserId (أُعيد توليد openapi:check). الترحيلات 20260929040000–20260929043000. النشر: شغّل فحص مديري المدارس (قراءة فقط) قبل الترحيل، ثم مهمّة نشر الإعدادات بعده (deploy/cloud-run/DEPLOY.md).

  • كل قيمة دخول تُستعمل مرة واحدة تُحفظ مُجزَّأة فقط. روابط استعادة كلمة المرور، وروابط الدخول السحرية، وتحدّيات مفاتيح المرور، وحالة الدخول بحساب Google، ورمز التسليم بعد الدخول بحساب Google، كلها الآن في جدول واحد ولا يُحفظ منها إلا بصمة SHA-256. كان challengeId لمفتاح المرور وstate الخاص بـ Google ورمز التسليم ?code= يُحفظ كما أُرسل، فكانت نسخة من قاعدة البيانات تكفي لإتمام دخول شخص آخر خلال الدقائق القليلة التي تصلح فيها. ما زالت كل قيمة صالحة لمرة واحدة ولوقت قصير، وتُرفض قيمة من نوع إذا قُدِّمت على أنها من نوع آخر. الروابط والرموز الصادرة قبل التحديث تبقى صالحة بعده.
  • إصلاح: لم يكن استيراد القوائم من جديد قادرًا على نقل مدير مدرسة إلى مدرسة أخرى. كان الاستيراد يرفض الدفعة كلها على أنها قديمة. صار لكل مدير مدرسة مؤشّر واحد إلى مدرسته، والنقل يُحرّر المدرسة السابقة.
  • مدير واحد لكل مدرسة تفرضه قاعدة البيانات على سجل المدير نفسه، وهو ما تقرؤه فحوص الصلاحيات دائمًا. حذف مدير المدرسة أو محو بياناته يُحرّر المدرسة، ويبقى سجله (مستواه).
  • لا تغيير على المستخدمين: أُزيل جدول الأدوار غير المستعمل وجدول ملف مدير المدارس الفارغ. دور المستخدم هو شخصيّته، ونطاق مدارس مدير المدارس محفوظ كما كان.

النقاط والشارات ولوحات التقدّم تمتلئ من تقدّم حقيقي — 2026-09-29

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (openapi:check سليم). لا ترحيل.

  • إصلاح: كان رصيد النقاط صفرًا لكل طالب، وكانت لوحات التقدّم كلها أصفارًا. لم تكن اللحظات المقيسة التي تستحق حدث إتقان تُسجَّل. صارت تُسجَّل الآن في معاملة قاعدة البيانات نفسها التي يُتّخذ فيها القرار:
    • انتقال مهارة من «متابعة» إلى «متمكّن» بناءً على أدلة جديدة (subskill_state_up)؛
    • تحسّن مهارة من ضعف إلى «متابعة» (skill_status_transition)؛
    • وصول مجال إلى «متمكّن» (domain_status_escalation)؛
    • اتجاه طلاقة أعلى من خطّ الهدف (cbm_trend_above_goal)؛
    • ارتفاع مستوى الصعوبة في التدريب (band_progression)؛
    • انتهاء خطة دعم لأنها حقّقت معيارها (bundle_completion).
  • ما لا يُحتفى به. أول تقييم (لا نموّ يُقاس منه بعد)، والقرار الذي لم يُحسم أو الذي لم يُقيَّم مجاله إلا جزئيًا، ونافذة اتجاه فيها تراجع حادّ، والخطة المنتهية لسبب آخر، وإعادة القرار على الأدلة نفسها: لا شيء من هذا يُسجَّل. وكل لحظة تُسجَّل مرة واحدة، فتكرار القرار نفسه لا يضيف شيئًا.
  • لا يُسجَّل بعد، عن قصد. «تحقيق هدف خطوة في الحزمة» (الخطط بلا خطوات في الموجة الأولى)، ورفع مستوى الدعم المتدرّج (لا يتغيّر إلا بتعديل من المعلّمة، لا بقياس).
  • لوحات التقدّم للصف ولصفوف المعلّمة وللمدرسة تُقرأ من هذه الأحداث عند الطلب. ولا لوحة تقدّم للطلاب، كما كان.

رصد الإجابات السريعة من زمن الإجابة — 2026-09-29

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة. الترحيل 20260929020000_p3c2_rbm_detector. النشر: شغّل مهمة نشر إصدار الإعدادات بعد الترحيل وقبل الإطلاق (deploy/cloud-run/DEPLOY.md)، وإلا توقّف رمز القرار الجديد عند إصدار لا يحتوي العتبة الجديدة.

  • مؤشرات السلوك تأتي الآن من إجابات حقيقية. الإجابة التي تُعطى في أقل من 300 ملّي ثانية (زمن السؤال بعد طرح زمن الإيقاف المؤقت) تُسجَّل مرة واحدة إجابةً سريعة (RBM-01) مرتبطةً بتلك الإجابة. وإذا كانت 40٪ أو أكثر من الإجابات المُقاسة زمنيًا لمهارة في جلسة واحدة سريعة، تُسجَّل الجلسة أيضًا مرة واحدة على أنها تخمين سريع محتمل (RBM-02). إجابات الورق والإجابات التي لم يُقَس زمنها لا تُعلَّم أبدًا. قبل ذلك لم يكن شيء يسجّل هذه المؤشرات، فلم تؤثّر في أي قرار.
  • ما الذي يغيّره المؤشر. الإجابة السريعة الواحدة معلومة فقط: تبقى الحالة كما هي، ولقطة حالة المهارة تذكر المؤشر. أما نسبة الإجابات السريعة على مهارة بوابية أو أساسية ضعيفة فلا تؤكّد الضعف ولا تفتح مجموعة التحقّق القصيرة، بل تحيل المهارة إلى مراجعة قصيرة لصلاحية القياس. المؤشر لا يغيّر أي علامة ولا يُنشئ ضعفًا أبدًا.
  • العتبات من الإعدادات. حدّ 300 ملّي ثانية هو العتبة الجديدة TH-RAPID-ITEM-01، ونسبة 40٪ هي TH-RAPID-SS-01 (ولم تكن لها قيمة). تُقرآن من إصدار الإعدادات الفعّال. حدّ 300 ملّي ثانية قيمة عمل مؤقتة إلى أن يؤكّد الشريك الرقم. ومحرّك أنماط الأخطاء في التدريب يستعمل الحدّ نفسه بدل نسخته الخاصة.
  • إعادة حساب القرار لا تكرّر المؤشرات. يُخزَّن كل مؤشر مرة واحدة لكل إجابة (أو جلسة) وقاعدة ومجموعة عتبات. العتبة المعدَّلة تسجّل مؤشرات جديدة بعد نشرها، والقرارات تقرأ فقط المؤشرات المسجّلة بالعتبات الحالية.

الحصص المباشرة تفتح أنشطتها، وحُذفت جداول غير مستخدمة، وأسماء المجالات تتبع تصنيف المهارات — 2026-09-29

حُذفت مسارات: مسارات جهاز العرض المخصَّص (POST .../personalized-projector/setup وGET .../answer-key وPOST .../mark وPOST .../commit)، وPOST /api/sync/sessions/{id}/observation، وGET /api/skill-dependencies. لم يعد POST /api/sync/sessions يقبل personalizedProjector، ولم يعد ملخّص الحصة يسرد الملاحظات، ولم يعد GET /api/sub-skills/{id} يضمّن dependencies. لم يكن تطبيق الويب يستدعي أيًّا منها (أُعيد توليد المواصفة وopenapi:check سليم). الترحيلات 20260929030000–20260929033000.

  • إصلاح: لم يكن الطالب يستطيع الإجابة في الحصة المباشرة. بدء الحصة يفتح الآن أول نشاط فيها، وكل «التالي» يفتح النشاط الذي يليه، ويذكر تدفّق الاستطلاع النشاط الذي يجيب عنه كل جهاز. قبل ذلك لم يُفتح أي نشاط، فلم يكن لدى شاشة الطالب ما تُرسل الإجابة إليه.
  • جهاز العرض المخصَّص وملاحظات القراءة الجهرية ينتقلان إلى الموجة الثانية. حُذفت مساراتهما وجداولهما الثلاثة.
  • حُذفت جداول لم يستخدمها أحد: قوالب الأنشطة الجماعية، وبيانات جودة الجلسة، وخريطة تبعيات المهارات الفارغة دائمًا، ولقطات لوحات الصدارة (تُحسب اللوحات عند قراءتها)، وفهرسا فئات الأخطاء وقواعد الأدلة (صارت فئات الأخطاء الثلاث عشرة قيدًا على جدول الأنماط الدقيقة).
  • بيانات جاهزية الإحماء تُحفظ في جلسة الإحماء نفسها. تُكتب مرة واحدة عند اكتمال الإحماء ولا يمكن تغييرها بعد ذلك.
  • جدول واحد لإعدادات المحرّكات. حدود أمانة التنفيذ، وأسابيع الخروج عن المسار، وحدّ اتجاه الطلاقة، وأوزان توصية الجلسات، ونِسَب حاجة الصف صارت في جدول واحد بإصدارات هو engine_parameters. القيم لم تتغيّر. النشر: شغّل pnpm config:publish بعد migrate deploy.
  • أسماء المجالات تطابق تصنيف المهارات. مؤشرات المجالات لدى مدير المدرسة ومدير المدارس تستخدم الآن أسماء المجالات العربية نفسها المستخدمة في بقية المنصة (مثلًا «دقة وطلاقة القراءة» بدل «الطلاقة والدقة»). أُرسلت التسميات السابقة إلى الشريك للتأكيد.
  • خريطة علاقات المهارات تغطّي المهارات الثمانين كلها. المهارتان اللتان أُضيفتا بعد خريطة الشريك (VOCAB-C06 وMORPH-C01) معلَّمتان بأن الشريك لم يربطهما بعد، ولم تُخترَع لهما أي علاقة.

استوديو الأسئلة يؤلّف أسئلة مطابقة الكلمة بمعناها — 2026-09-26

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (openapi:check سليم). لا ترحيل.

  • قالب إنتاج جديد COMPREHENSION_WORD_MATCHING (productionKind {kind: "match_pairs"}) مثبَّت على نوع السؤال بالاسم نفسه، ويظهر في GET /api/templates. يحتاج قطعة مرتبطة ومفتاح أزواج صحيحًا: الشرط الجديد needsMatchPairs يطبّق القاعدة نفسها التي تطبّقها بوابة الاستيراد وPATCH /api/items/{id} (من 2 إلى 6 أزواج، كلمات ومعانٍ غير مكرّرة، معانٍ إضافية مختلفة عن الحقيقية، 8 معانٍ على الأكثر). لا يأخذ السؤال القالب إن لم يستوفِها (يعيد POST /api/items/preview والتعديل 422 مع السبب بالعربية). ولا يغيّر القالب ما يُقدَّم للطالب: النوع نفسه يقدّم لوحة match_pairs. أما قوالب المطابقة التجريبية (PAIR_DRAG_COLUMNS وDRAG_MATCH_BOARD وMATCH_LETTER_FORMS وRHYME_MATCH) فتبقى للمعاينة فقط.
  • النوع مشتقّ التقديم: لا يُسنَد إليه قالب اختيار من متعدد أو اختيار متعدد، ولا يُسنِد التعبئة التلقائية إليه إلا قالبه.
  • يحرّر استوديو الأسئلة الأزواج والمعاني الإضافية، ويوقف الحفظ بالقواعد نفسها، ويقيّم لوحة الطالب في المعاينة. النشر: شغّل seed-main مرة واحدة ليصل صفّ القالب (وصفّ نوع السؤال من P8) إلى جداول الكتالوج.

القرارات تقرأ حكم العام الدراسي الحالي، والقياس المتأخر يحتفظ بعامه، وغياب مفتاح منصات التعلّم يُبلَّغ بوضوح — 2026-09-28

ثلاثة مسارات صار لها ردّ 503 موثَّق (أُعيد توليد المواصفة وopenapi:check سليم)، ولم يتغيّر شكل أي طلب أو استجابة آخر.

  • إصلاح: كان نقل المستوى قد يعتمد على حكم متابعة من العام الماضي. صارت أدلة نقل المستوى، وإشارة المتابعة في نظام الاستجابة للتدخّل، وإشارة النموّ في أمانة التنفيذ، وضابط التفعيل، وملفّ غرفة البيانات، تقرأ حكم العام الدراسي الحالي للطالب فقط. كانت في بداية العام الجديد تقرأ حكم حزيران الماضي بجانب قياسات هذا العام التي لم تُسجَّل بعد. غياب حكم في هذا العام يُعدّ «لم يُقرَّر بعد».
  • إصلاح: كان القياس المُدخَل متأخرًا يُنسب إلى العام الجديد. قياس المتابعة أو قراءة الطلاقة أو قراءة قائمة الكلمات المؤرَّخة قبل الترفيع تحتفظ الآن بالعام الدراسي للصف الذي كان فيه الطالب حينها، فلا تتسرّب إلى أول قرار في العام الجديد.
  • غياب مفتاح تشفير منصات التعلّم يُبلَّغ بوضوح. صار رفع ملفات OneRoster وقراءة المساقات ومعاينة الاستيراد تجيب بـ 503 SSO_NOT_CONFIGURED بدل خطأ 500 عامّ، ولا يُخزَّن شيء. والمزامنة التي لا تستطيع فتح التفويض تسجّل تشغيلًا فاشلًا (token_key_missing) وتُبقي الاتصال فعّالًا.
  • ترتيب ثابت لسجلّ قرارات المستوى. القرارات المتّخذة في اللحظة نفسها تُعرض من الأحدث بحسب ترتيب تسجيلها، وبالترتيب نفسه في كل مرة.

الأوقات بمنطقة زمنية، وبصمة واحدة مملّحة لعنوان IP، وتشفير رموز منصات التعلّم — 2026-09-28

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (openapi:check سليم). الترحيلات 20260928030000_p3b3_timestamptz و20260928031000_p3b3_ip_hash_single_helper و20260928032000_p3b3_lms_tokens_encrypted.

  • كل وقت مخزَّن لحظةٌ محدّدة. كان 62 عمودًا بلا منطقة زمنية، في جداول المستخدمين والجلسات ورموز الدخول وسجلّ أحداث الدخول والمؤسسات والمدارس والصفوف والتسجيل ومنصات التعلّم والتجربة. صارت كلها timestamptz، وحُوّلت على أنها بتوقيت UTC فلم تتغيّر أي لحظة مخزّنة. كانت جلسة قاعدة البيانات التي تعمل بمنطقة زمنية أخرى تقرؤها مُزاحة بفارق تلك المنطقة. أُعيد بناء سجلّ أحداث الدخول بأقسامه الشهرية نفسها.
  • عناوين IP المخزّنة بصمات مملّحة دائمًا. كان سجلّ أحداث الدخول ورموز رابط الدخول يحفظان بصمة غير مملّحة يمكن عكسها إلى العنوان، وكان سجلّ التدقيق الأمني يحفظ العنوان نفسه. صارت كلها تحفظ البصمة المملّحة نفسها التي يستعملها نموذج التواصل والتجربة. الملح مشتقّ من AUTH_JWT_SECRET وليس مفتاح التوقيع نفسه. مُسحت القيم القديمة لأنه لا يمكن تمليحها بعد تخزينها.
  • رموز ربط منصات التعلّم مشفّرة. رموز الوصول والتحديث من Google Classroom وملفات OneRoster تُشفَّر بخوارزمية AES-256-GCM بالمفتاح الجديد LMS_TOKEN_KEY، وقاعدة البيانات ترفض الرمز غير المشفّر. من دون المفتاح يُجيب ربط المنصة بالرمز 503 ولا يُخزَّن شيء. الاتصال الذي كان يحمل رموزًا غير مشفّرة أُعيد إلى الحالة revoked، فيعيد المسؤول ربطه. النشر: أنشئ السرّ lms-token-key قبل النشر (deploy/cloud-run/DEPLOY.md).

متابعة التقدّم والطلاقة لكل سنة دراسية، وقرارات المستوى تسجّل انتقالها — 2026-09-28

لا عمليات جديدة. تضاف حقول إلى استجابتين ويضيق حقل في طلب واحد (أُعيد توليد openapi:check). الترحيل 20260928010000_p3b1_year_window_tier.

  • إصلاح: خطة امتدت عبر العطلة الصيفية كانت تحكم على السنة الجديدة من قياسات السنة الماضية. صارت أدلة المتابعة وأحكامها وتنبيهات التراجع الحاد تحمل السنة الدراسية (مثل 2026-2027) مأخوذة من صف الطالب. الحكم يقرأ أدلة سنته فقط، وإعادة الحساب في سنة جديدة حكم جديد، لا حكم السنة الماضية على أنه «محسوم من قبل».
  • إصلاح: التراجع في سنة جديدة كان يعيد استخدام تنبيه السنة الماضية المفتوح. تنبيه التراجع الحاد ينتقل مع الطالب إلى صفه الجديد، فكان التراجع في السنة الجديدة يجد تنبيه السنة الماضية المفتوح للنافذة نفسها ولا يفتح تنبيهه. صار يُحفظ تنبيه مفتوح واحد لكل طالب وصف وسنة دراسية ونافذة. البوابات التي تسأل «هل ما زال تنبيه مفتوحًا» لم تتغيّر: التنبيه الذي لم يُراجَع من سنة سابقة ما زال يعني المراجعة أولًا.
  • إصلاح: ملخّص الطلاقة قد يعرض قراءة السنة الماضية على أنها قراءة هذه السنة. قياسات القراءة الجهرية (cbm_scores) تحمل سنتها الدراسية، وملخّصا الطلاقة للصف والمدرسة يقرآن قياسات سنة كل صف فقط.
  • الحقل window في POST /api/monitoring/evidence يقبل BOY أو MOY أو EOY فقط (كان أي نص يُخزَّن كما هو؛ صار خطأ 400). النوافذ المخزّنة قيم نافذة محدّدة النوع.
  • GET /api/monitoring/alerts يعيد academicYear لكل تنبيه، وassessmentWindowId صار BOY أو MOY أو EOY أو فارغًا.
  • قرارات المستوى تسجّل الانتقال الذي أحدثته. يعيد GET /api/students/{id}/tier-decisions الحقلين fromTier وtoTier لكل قرار، ويعرضهما سجل القرارات في غرفة البيانات. يُكتبان مع تغيير المستوى نفسه، فلم يعد التصعيد في أعلى مستوى (دون انتقال) يلتبس بانتقال حقيقي. وترفض قاعدة البيانات قرارًا جديدًا بدونهما أو بانتقال لا يطابق نوع القرار.
  • لقطات حالة المهارة والمجال والمجال الكبير يجب أن تحمل سنة دراسية. أُزيلت القيمة الافتراضية الفارغة وصار شكل السنة مُتحقَّقًا منه.
  • الصفوف الموجودة أُعطيت السنة الدراسية لصف الطالب وقت كتابة الصف (القاعدة نفسها في تغيير 2026-09-26). وقرارات المستوى السابقة أُعطيت fromTier وtoTier بإعادة تشغيل قرارات كل طالب بالترتيب؛ وحيث لا تنتهي الإعادة عند مستوى الطالب الحالي تبقى فارغة ولا تُخمَّن. والنافذة المخزّنة التي ليست BOY أو MOY أو EOY توقف الترحيل وتذكر القيمة.

مراجع حقيقية، وسجلّات تدقيق تحميها قاعدة البيانات، ومفردات لهجة واحدة — 2026-09-28

لا عمليات جديدة، ولم يتغيّر شكل أي استجابة (openapi:check سليم). الترحيلات 20260928020000_p3b2_soft_ref_fks و20260928020100_p3b2_append_only_triggers و20260928020200_p3b2_controlled_vocabularies.

  • صار 43 مرجعًا كانت أرقامًا مجرّدة مفاتيحَ أجنبية حقيقية: جلسات الدرس المتزامن ومشاركوها ومجموعاتها وأنشطتها وإجاباتها، وطلبات المدير، وأحكام المتابعة ولقطات الالتزام بالتنفيذ وقرارات مستوى الدعم وتثبيت التجميع، والجلسات المولَّدة ومخطّطاتها وعمليات التجميع، وجلسات القراءة الجهرية ونصوصها، وصفوف الأدلّة ولقطات الحالة المُطلِقة وقيود عكس النقاط، ومؤشّرات بنك الأسئلة. يُرفض أي صف يشير إلى طالب أو جلسة أو خطة أو نص غير موجود، أو إلى مدرسة أو جلسة متزامنة لمؤسسة أخرى.
  • كل صف لدرجة القراءة الجهرية يشير الآن إلى جلسة القراءة التي أُخذ منها (cbm_scores.oralReadingAssessmentId). ربط الترحيلُ الصفوفَ الموجودة.
  • الطلب POST /api/sync/sessions/{id}/responses يعيد 404 إذا لم يكن activityRunId نشاطًا في تلك الجلسة. كان يخزّن أي نص.
  • صارت 22 جدولًا إضافيًا للإلحاق فقط بقادح في قاعدة البيانات، منها سجلّات الدخول والأمان، ومراجعات الأسئلة والنصوص، وخطط المتابعة، وعلامات تعديل البرنامج، وسجلّات الجلسات، وتنبيهات المنصّة، وأحداث التهيئة، وعمليات التجميع، وسجلّات الوصول والإعداد، وسجلّ الملفات. مسار المحو يفتح نافذة الصيانة حول الصفوف التي يمحوها فقط.
  • مفردات لهجة واحدة. تُخزَّن لهجة الطالب في البيت بالقيمتين msa وlevantine، وهما القيمتان المستعملتان في الأسئلة وفي التسليم. واجهة المستخدمين وملف القائمة ما زالتا تقبلان MSA وLEV وتعيدانهما.
  • استيراد الأسئلة يتحقّق من dialect_tags وevidence_type. وسوم اللهجة المقبولة هي msa وlevantine وlev بأي حالة أحرف. يُحذف رمزا البلد PS وJO. أي وسم آخر يرفض الصف بسبب missing_metadata، وكذلك قيمة evidence_type التي ليست نوعَ دليل. حُوّلت الأسئلة المخزّنة: صار ["msa","PS"] هو ["msa"]، والأسئلة الستة من الشريك التي كان نوع دليلها audio صارت بلا نوع دليل.

رحلة الطالب v2 — القطعة بجانب أسئلتها، مطابقة الكلمة بمعناها، وتقييم كل جزء على حدة — 2026-09-26

لوحة الشريك D-02 (2026-09-26) وقرارات محمد الأربعة في اليوم نفسه. لا عمليات جديدة. الترحيلان 20260928040000_practice_opened_by و20260928040100_comprehension_word_matching.

  • نوع سؤال جديد COMPREHENSION_WORD_MATCHING (استراتيجية التصحيح pair_mapping): يسحب الطفل كل كلمة إلى معناها. المفتاح interactionKey = {kind: "match_pairs", pairs: [{l, r}], extraRights?: [...]} بالنصوص (من 2 إلى 6 أزواج، كلمات ومعانٍ غير مكرّرة، ومعانٍ إضافية مختلفة عن الحقيقية، و8 معانٍ على الأكثر). تتحقّق منه بوابة الاستيراد و PATCH /api/items/{id} وتحفظانه بصيغة موحّدة؛ ويحتاج — ككل صفوف COMPREHENSION_* — إلى قطعة وعملية قراءة وموضع إجابة. يُقدِّم GET /api/items/{id}?view=served الحقل interaction = {kind: "match_pairs", left, right}: الكلمات بترتيب التأليف والمعاني بترتيب ثابت في الجلسة لا يطابق الكلمات صفًا بصف. والإجابة {v: 1, kind: "match_pairs", pairs: [{l, r}]}، وتُصحَّح كلها أو لا شيء (يبقى θ ثنائيًا).
  • تقييم كل جزء في التدريب (POST /api/practice/queues/current/submit-response): تحمل الاستجابة parts: [{part, correct}] بعد الخطأ الأول في سؤال ذي أجزاء (زوج مطابقة: الجزء هو الكلمة؛ فراغ في إكمال متعدد: الجزء رقم الفراغ من 0؛ موضع في ترتيب: الجزء رقم الموضع من 0) — أحكام فقط بلا إجابات. وبعد الخطأ الثاني يذكر correctAnswer.parts: [{part, answer}] الأجزاء التي بقيت خاطئة فقط. وكلاهما null للأسئلة ذات الإجابة الواحدة. ويبقى الحكم المحفوظ وθ على مستوى السؤال كله.
  • استراحة التقييم المعمّق بعد القطع الطويلة فقط: استُبدل partSize في حالة الجلسة بـ breakBefore: boolean — true على السؤال الذي يلي قطعة قراءة من 80 كلمة فأكثر.
  • أي تدريب مفتوح: يحمل GET /api/practice/students/{id}/training-sessions الحقل currentTraining ({openedAt, openedBy: "automatic" | "teacher"} | null)، من العمود الجديد student_session_practice.openedByUserId (يُملأ حين تستخدم المعلّمة «تعيين التدريب»).

قواعد القرار تُقرأ من أعمدة ذات أنواع محدّدة، وحذف الجلسات المنتهية وسجلّات تحديد المحاولات — 2026-09-27

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (openapi:check سليم). الترحيلان 20260927030000_p3a3_typed_rule_columns و20260927030100_p3a3_drop_duplicate_auth_indexes.

  • قواعد حالة المهارة لم تعد تعتمد على JSON مخزّن في حقل الملاحظات. صارت أعمدةً ذات أنواع محدّدة: علامة الحوكمة في القاعدة ADR-GOV-01، ومجموعات الأنماط البديلة في قواعد ADR وPAC وSSR، ونطاق قواعد CIS وحدّها الأعلى من البنود وشرط فتح البند الثالث، ومعرّفات قواعد الأنماط وحالات المجال وربط المجالات الكبيرة. كانت الملاحظات التي يتعذّر تحليلها تُعامَل كأنها فارغة، فقد تتحوّل ADR-GOV-01 بصمت إلى قاعدة عادية. الملاحظات الآن للتوثيق فقط.
  • قواعد الملف الشخصي تُتحقّق منها ولا تُخمَّن. نمط كل قاعدة عمود JSON يُتحقّق من صحته. قرار منع التداخل وقائمة الصفوف والمعدِّلات المسموحة ومستوى الثقة أعمدة ذات أنواع محدّدة. كانت عبارة الثقة غير المعروفة تصبح moderate، والنمط الذي يتعذّر تحليله يجعل القاعدة لا تطابق أحدًا (أو تطابق الجميع في القاعدة الأساسية). البذر يرفض الآن مثل هذا الصف.
  • القيمة الناقصة أو غير الصحيحة في قاعدة توقف إعادة الحساب بخطأ مسمّى (SseRuleValueError وProfileCatalogValueError) بدل قيمة افتراضية. ونشر إصدار الإعدادات يرفض النمط غير الصحيح أيضًا. الإصدارات المنشورة قبل هذا التغيير ما زالت قابلة لإعادة التشغيل: تُحوَّل صفوفها المخزّنة عند القراءة، والمحتوى القديم التالف خطأ.
  • حوّل الترحيل الصفوف الموجودة من النص القديم. مجموعات القواعد المحمّلة مطابقة لما كانت عليه بايتًا ببايت، فلم يتغيّر أي قرار.
  • يحذف auth:purge الليلي الآن الجلسات التي انتهت صلاحيتها منذ أكثر من AUTH_PURGE_INACTIVE_SESSION_DAYS يومًا ولو لم يسجّل أحد الخروج. كان يحذف الجلسات الملغاة فقط، فتبقى بصمات رموزها إلى الأبد. ويحذف كذلك صفوف تحديد المحاولات الهادئة بعد انقضاء نافذة كل محدِّد وغير المقفلة. مفاتيح هذه الصفوف هي البريد أو العنوان الذي يكتبه أي شخص، فكان الجدول ينمو بلا حدّ. التشغيل يُبلغ عن عدد جديد rateLimitWindow.
  • حُذف فهرسان يكرّران الفهرس الفريد على العمود نفسه: Session.token وUser.email.

سلسلة قرارات الاستجابة للتدخّل: إشارات كانت تُقرأ ولا تُكتب — 2026-09-27

لا عمليات جديدة، ولم يتغيّر شكل أي استجابة (openapi:check سليم). صارت بعض الحقول تحمل قيمة بعد أن كانت فارغة دائمًا. الترحيلات من 20260927020000 إلى 20260927025000.

  • «التأكيد والتصعيد» من المعلّم يصل الآن إلى المراجِع. الطلب POST /api/workflow/review مع dispositionType: escalated يفتح طلب مراجعة لمستوى الدعم في القائمة نفسها التي يقرؤها المدير والمعتمِد (tier_review_request مع حزمة قرار)، وtierReviewRequestId في الاستجابة هو معرّف هذا الطلب. إذا كانت للطفل مراجعة جارية ارتبط التصعيد بها. حُذف الجدول القديم teacher_review_request لأن أحدًا لم يكن يقرؤه.
  • تُرفض جلسة الحزمة ما دام تنبيه التراجع الحادّ مفتوحًا. صار قيد مُجمِّع الجلسات يقرأ تنبيه التراجع الحادّ المفتوح (التنبيه الذي يراجعه المعلّم). كان يقرأ نوع تنبيه لا يكتبه شيء، فلم يرفض أي جلسة. حُذف من rti_alert النوعان acute_regression_review وtier_review_due لأنهما لم يُكتبا قط.
  • الخطة المُنهاة تُظهر سبب إنهائها. سجلّ الخطط لدى المدير (GET /api/principal/students/{id}/plan?includeHistory=true) يعيد exitReasonCode وتسميته من انتقال الإنهاء في سجلّ حالات الخطة. حُذفت تسعة أعمدة من bundle_assignment لم تُكتب قط. وصار activePlan.objectType في تقرير الطالب يُؤخذ من تعريف الحزمة فيظهر بقيمته.
  • إشارة «غرفة البيانات مطلوبة» تعمل. يُحتسب الطالب في صفه إذا كانت له حزمة قرار مفتوحة لمراجعة المستوى أو لمراجعة الاستمرار (مسودة أو قيد المراجعة). كانت تقرأ عمودًا لا يكتبه شيء فلم تظهر قط.
  • مستوى الدعم الموصى به في شارة المستوى صار يظهر. كل قرار في مستوى الدعم يضبط recommendedSupportIntensity على ما يوافق المستوى الناتج (universal أو targeted أو intensive)، وعُبّئت الصفوف الموجودة.
  • لم تعد أحكام المتابعة تتكرّر. إعادة الحساب على الأدلّة والوصفة والقواعد نفسها تعيد الحكم المخزَّن بدل كتابة حكم جديد، والدليل الجديد يضيف حكمًا واحدًا. تسجيل دليل واحد يكتب الآن حكمًا واحدًا لا حكمين.
  • إعدادات الأمانة في التطبيق والمتابعة صارت إعدادات حقيقية. حدود تقدير الأمانة (0.80 / 0.60 / 0.40) وإعدادات المتابعة (الخروج عن المسار بعد 3 أسابيع، ودورة تخطيط من 6 أسابيع ما زال الشريك مدينًا بها ضمن Q-FID-CYCLE) صارت صفوفًا مزروعة في كل إصدار إعدادات، والمحمِّلات ترفض العمل من دونها بدل قيم افتراضية مخفية. النشر: شغّل مهمة نشر الإعدادات بعد الترحيلات.

كل مدرسة تحدّد متى يبدأ عامها الدراسي، والفحص ينتظر الترحيل إلى العام الجديد — 2026-09-26

عمليات تغيّرت: POST /api/schools وPATCH /api/schools/{id} وكل استجابة للمدرسة تحمل schoolYearStartsOn؛ وGET /api/organizations/{orgId}/school-years واستجابة الترحيل تحملان rolloverDue وrolloverDueSchoolIds؛ وقد يردّ POST /api/diagnostic-sessions/start بالرمز 409 والسبب year_not_rolled_over؛ وأُضيفت القيمة year_not_rolled_over إلى screeningState في خطة يوم الطالب وإلى projection.skippedReason في القراءة الجهرية وقوائم الكلمات (openapi:check سليم). الترحيل 20260928050000_school_year_start_per_school.

  • قاعدة واحدة للعام الدراسي. كان الفحص يحسب العام الدراسي من 1 آب بينما تمتد صفوف school_year من 1 أيلول، فكان جانب الطالب وصفوف الأعوام يختلفان في شهر آب على أيّ عام هو (فحص نهاية العام في حزيران كان يتوقّف احتسابه في 1 آب). صار العام الدراسي يبدأ في 1 أيلول في كل مكان ما لم تحدّد المدرسة بدايتها.
  • schoolYearStartsOn للمدرسة: بصيغة "MM-DD" بين 07-01 و10-31 على التقويم المحلي للمؤسسة، وnull تعني 1 أيلول. يحدّد «هذا العام الدراسي» في الفحص (فحص واحد لكل نافذة في العام). على المدرسة التي تفتح أبوابها في أواخر آب (افتتحت المدارس الحكومية في الأردن في 23 آب 2026) أن تضبطه، وإلا احتُسبت فحوصها في آب ضمن العام السابق. القيمة غير الصالحة تُرفض بالرمز 422.
  • إصلاح: كان الفحص الذي يُجرى قبل الترحيل يُسجَّل تحت العام الماضي. إذا كانت نافذة فحص مفتوحة وصفّ الطالب ما زال يحمل عامًا دراسيًا انتهى بحسب يوم بداية مدرسته، فلا يُعرض الفحص ولا يبدأ (year_not_rolled_over، والرمز 409 عند البدء، حتى إن سمّى المعلّم أو المشرف النافذة)، وتُحفظ القراءة الجهرية أو قائمة الكلمات التي يقيّمها المعلّم من دون أن تدخل في صورة المهارات (skippedReason: year_not_rolled_over)، ويرى الطفل لوحة الانتظار الهادئة نفسها كما في أي يوم لا مهمة فيه. قبل ذلك كانت الجلسة تُخزَّن تحت تسمية العام الماضي، وبعد الترحيل يبدو كأن الطالب فُحص من قبل.
  • rolloverDue في العام الدراسي النشط يصبح صحيحًا حين تبدأ أيّ مدرسة من مدارس المؤسسة عامها التالي، وrolloverDueSchoolIds تسمّي هذه المدارس. رحّل العام (POST …/school-years/{yearId}/promote) لإعادة فتح الفحص.
  • يبقى startsOn وendsOn في صف school_year على البداية الافتراضية (1 أيلول ← 31 آب) وهما للعرض فقط. والطالب الذي لا صف له يُحسب عامه من البداية الافتراضية على التقويم المحلي (كان 1 آب وبتوقيت UTC).

أدلّة الفحص والملفات التعليمية تُحفظ لكل سنة دراسية — 2026-09-26

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (openapi:check سليم). الترحيل 20260927010000_p3a1_windowed_rows_academic_year.

  • إصلاح: كان الفحص الجديد للطالب العائد يُحسم جزئيًا من فحص العام الماضي. الصفوف التي تُحسب منها حالة المهارة (إجابات الفحص لكل مهارة، ونتائج القراءة الجهرية وقوائم الكلمات، وإجابات مجموعات التأكيد المصغّرة ونتائجها، ومراجعات الصلاحية، وتصنيفات الأنماط، ونتائج الجلسات) كانت تُخزَّن حسب نافذة التقييم (BOY وMOY وEOY) من دون سنة دراسية. لذلك كان فحص BOY في السنة الثانية يقرأ صفوف BOY من السنة الأولى أيضًا، ويحتسب مهارات العام الماضي ضمن تغطية المجال هذا العام، وقد يلتقط مجموعة تأكيد مصغّرة لم تكتمل في العام الماضي. صار كل صف من هذه الصفوف يحمل سنته الدراسية (مثل 2026-2027) المأخوذة من صف الطالب، ولا يقرأ أي قرار إلا صفوف السنة الحالية.
  • إصلاح: جلسة لم تكتمل في العام الماضي كانت تمنع جلسة هذا العام أو تُستأنف مكانها. صارت جلسات التشخيص ومجموعات التأكيد المستحقة تحمل السنة الدراسية أيضًا، وقاعدة «جلسة مفتوحة واحدة لكل نافذة» صارت لكل سنة دراسية.
  • إصلاح: قد يُسجَّل الملف التعليمي مرتين، أو يُطابَق ملف العام الماضي. قاعدة «ملف معلّق واحد لكل طالب وسنة دراسية ونافذة وملف ومجموعة قواعد» تفرضها قاعدة البيانات الآن: حسابان متزامنان يتركان صفًا واحدًا، وحساب السنة الدراسية الجديدة ينشئ ملفًا معلّقًا جديدًا لا ملف العام الماضي.
  • الصفوف الموجودة أُعطيت السنة الدراسية للصف الذي كان فيه الطالب وقت كتابة الصف (وإلا فالسنة الدراسية للمؤسسة التي تشمل ذلك التاريخ، وإلا فالسنة الدراسية التقويمية التي تبدأ في 1 آب). مراجعات الصلاحية المعروضة في تقارير المعلّم هي مراجعات السنة الدراسية الحالية.

رحلة الطالب (النسخة 2) — المهمة الثانية على أجزاء، النجوم والشارات، فحص الصوت — 2026-09-26

وفق مسار الشريك J-00 (§0 و§4 و§8) والقرارين D-A وD-D. الفحص الأعمق على أجزاء: صارت حالة جلسة الطالب (start وstate وresume وresponses) تحمل partSize — 6 لجلسة d_triggered وnull لغيرها — ويعرض المشغّل شاشة استراحة بعد كل جزء مكتمل (عرض فقط: لم يتغيّر اختيار الأسئلة ولا قاعدة التوقّف ولا الحدّ الزمني). وبطاقة second_assessment في today-plan صارت resume: false حتى الإجابة الأولى. النجوم والشارات (D-A): أُضيف reward (stars وnewBadge، وnull عند إعادة الإرسال) إلى POST /api/practice/training/today/feedback، وrewards (stars وbadges[]) إلى GET /api/student/today-plan — نجمة لكل يوم تدريب منتهٍ، وشارات للجهد (1 و5 و10 و20 يومًا) وللمواظبة (3 أيام في أسبوع)؛ تُشتقّ من training_session، وليست نقاط خبرة ولا تُرتَّب. النشاط: نوعان جديدان من العميل: student_login_completed (mode وmsToLogin وfailedAttempts وhelpOpened — دون أي شيء مما كُتب) وsound_check (heard وplays)؛ وأُضيف task اختياريًا إلى next_action_result. أُصلح: رفضُ دفعة النشاط في كل تحميل للصفحة الرئيسية (بسبب المفتاح task)، وخطأ الترطيب عند استئناف جلسة من بطاقة الصفحة الرئيسية الذي كان يُضيّع أول نقرة للطفل.

رحلة الطالب (النسخة 2) — يوم التدريب: محاولتان، «كيف كان التدريب؟»، «تعيين التدريب» — 2026-09-26

وفق مسار الشريك J-00 والعرض التفاعلي D-01. أصبح التدريب يومًا تدريبيًا: تمرين التفكير ثم التمارين ثم سؤال «كيف كان التدريب؟» الإلزامي. محاولتان لكل سؤال: الخطأ الأوّل يُبقي السؤال نفسه مع تلميح المشتّت المختار؛ والمحاولة الثانية تُسجَّل لكنها لا تُحتسب أبدًا في القياس (θ وتوجيه الكتلة 80/60 ومحرّك الأنماط تقرأ المحاولة الأولى فقط)؛ والخطأ الثاني يكشف الإجابة الصحيحة. تدريب واحد في اليوم، ولا تدريب ما دام فحص أعمق مقترحًا أو معتمدًا أو مفتوحًا. لم يعد الإحماء قابلًا للتخطّي، ولم يعد يسبق التقييم. الواجهة البرمجية: حقول جديدة outcome وattempt وcorrectAnswer وtraining في submit-response، وretry وtraining في next-item، وretryItemId وtraining في queues/current/state (قراءة فقط)؛ وعمليات جديدة: POST /api/practice/training/today/feedback وGET /api/practice/students/{studentId}/training-sessions وPOST /api/practice/students/{studentId}/assign-training. جدول جديد training_session. أُصلح: إعادة التحقّق من قائمة التسجيلات الصوتية عند كل تحميل، وقبول أحداث plan_action التي ترسلها بطاقة الفحص الأعمق.

قوائم التدريب وتنبيهات التراجع الحادّ عند إعادة القياس أو الانتقال بين الصفوف — 2026-09-26

لا عمليات جديدة، ولم يتغيّر شكل أي استجابة.

  • إعادة التشخيص تحفظ سجلّ قائمة التدريب المنتهية. ما زال فتح إعادة التشخيص يؤرشف كل قوائم التدريب السابقة، لكن القائمة غير المنتهية وحدها (نشطة أو متوقفة) تصبح abandoned. القائمة التي أنهاها الطفل تبقى complete (مؤرشفة) ولا يُعاد كتابتها.
  • تنبيه التراجع الحادّ المفتوح ينتقل مع الطالب. عند تسجيل الطالب في صف آخر (انتقال، أو استيراد قائمة، أو ترفيع السنة الدراسية) تنتقل تنبيهاته المفتوحة إلى الصف الجديد: يراها المعلّم الجديد، وإذا قيس التراجع نفسه مجددًا في الصف الجديد وُجد التنبيه القائم بدل فتح تنبيه ثانٍ.

مراجعة بنية قاعدة البيانات × البرنامج التجريبي الأول: توحيد الفرعين — 2026-09-26

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (openapi:check سليم، 389 مسارًا). الترحيلات: أربعة ترحيلات تمهيدية (20260923125000 و20260925045000 و20260925055000 و20260925090000) تسمح لترحيلات البرنامج التجريبي المنشورة ولترحيلات المراجعة بالعمل بترتيب زمني واحد، وترحيلان لنقل البيانات (20260926010050 و20260926050050)، وزوج التوحيد 20260926110000 / 20260926110100.

  • تبقى مراجعة الأساس هي الأحدث (D-SYNC-1). مفاتيح لقطات المهارة والمجال والمجال الكبير هي (الطالب، المهارة أو المجال، السنة الدراسية، النافذة، بصمة الإعدادات، basisRevision): الأساس نفسه تحت القواعد نفسها لا يكتب صفًّا جديدًا، والأساس المتغيّر (مجموعة تأكيد قصيرة تحسم مهارة معلّقة، أو قياس قراءة جهرية جديد في النافذة نفسها) يضيف مراجعة جديدة. كل قراءة «للأحدث» ترتّب بالسنة ثم إصدار الإعدادات ثم مراجعة الأساس ثم وقت الحساب ثم المعرّف، وأُعيد بناء أعداد لوحة المدير بهذه القاعدة.
  • بيانات البرنامج التجريبي صارت في الجداول الموحّدة. مستوى الدعم عند كل محاولة تدريب في صفّ الإجابة (item_response)، ونوع تجربة التدريب ومؤشّر الاستبدال في student_session_practice (ونوع التجربة يسمّي إصدار الإعدادات الذي قُرئ منه)، وتوصية الفحص الأعمق تشير إلى جلستها بمفتاح أجنبي حقيقي وسجلّها في status_transition، ونتيجة قائمة الكلمات تحمل معرّف طالب واحدًا وإصدار الإعدادات الذي جاء منه المستوى. نُقلت الصفوف الموجودة ولم يُحذف منها شيء.
  • كتالوجات البرنامج التجريبي صارت جزءًا من إصدارات الإعدادات — عشرة جداول يملكها الشريك تُلتقط في كل إصدار وتُقرأ منه.
  • سلسلة الملف ثم تنبيهات الاستجابة للتدخّل تعمل مع كل مصدر أدلّة (التشخيص، والقراءة الجهرية، وقوائم الكلمات، وإعادة الحساب بعد مجموعة التأكيد)، لا عند إنهاء التشخيص فقط.
  • أداة purge:demo-tenants تعمل على أي إصدار من المخطّط (تقرأ ترتيب الحذف من قاعدة البيانات الحيّة) — تُشغَّل قبل النشر كما يشترط WP-S10.

مراجعة بنية قاعدة البيانات — المرحلة 1C: جدول مرحلي واحد لاستيراد القوائم ونظام إدارة التعلّم — 2026-09-26

لا عمليات جديدة، ولم يتغيّر شكل أي طلب أو استجابة (openapi:check سليم). الترحيلان 20260926100000_import_job و20260926100100_import_job_drop_legacy.

  • صارت دفعات استيراد ملفات القوائم ومعاينات استيراد نظام إدارة التعلّم تُحفظ في جدولين فقط، import_job وimport_row، مع نوع roster_csv أو lms_roster. نسخ الترحيل كل دفعة ومعاينة وصفّ مع الإبقاء على معرّفات الدفعات والمعاينات (ومعرّفات صفوف القوائم)، فيبقى معالج الاستيراد المفتوح يعمل. حُذفت الجداول roster_import_batch وroster_import_row وlms_import_preview. يبقى سجلّ عمليات مزامنة نظام إدارة التعلّم سجلًّا مستقلًّا لا يُعدَّل، وصار يذكر المعاينة التي أنشأتها كل عملية أو اعتمدتها.
  • إصلاح: إعادة اعتماد معاينة قديمة من نظام إدارة التعلّم كانت تعيد آخر عملية مزامنة للاتصال بدل عمليتها هي. صارت تعيد عملية تلك المعاينة.
  • إصلاح: اعتماد المعاينة نفسها مرّتين في اللحظة نفسها كان قد يضيف الأشخاص مرّتين ويسجّل عمليتَي مزامنة. صار الاعتماد الثاني ينتظر ثم يعيد نتيجة الأوّل.
  • إصلاح: المزامنة الليلية التلقائية كانت تظهر في سجلّ المزامنة كأنها اعتماد يدوي من المسؤول. صارت تظهر بـtriggeredBy: cron وautoApplied: true.
  • إصلاح: محو بيانات شخص صار يزيل صفوفه أيضًا من معاينات نظام إدارة التعلّم التي اعتُمدت (كان يُنظّف المعاينات التي تنتظر المراجعة فقط). وتُحسب هذه الصفوف في counts باسم import_row (بدل roster_import_row وlms_import_preview).

مراجعة بنية قاعدة البيانات — المرحلة 2e-2: محو حساب مستخدم بالغ — 2026-09-25

عملية جديدة POST /api/users/{userId}/erase (الوسم erasure، الملف wp-erasure.yaml). الترحيل 20260926070000_audit_action_person_erased.

  • يستطيع المسؤول العام الآن محو بيانات معلّم أو وليّ أمر أو مدير أو مدير مدارس أو مسؤول في مكانها، بالطريقة نفسها التي يُمحى بها الطالب. تُزال الأسماء والبريد الإلكتروني واسم المستخدم والهاتف ومرجع الموظّف ومفاتيح المرور وربط Google ونظام إدارة التعلّم والإشعارات الموجّهة إلى الشخص، ورقم هاتف وليّ الأمر وربطه بأطفاله. ويُزال عنوان بريد الشخص أينما سجّله تاريخ تسجيل الدخول، حتى على سجلّ حساب آخر (مثلًا بصفته مستلم رمز دخول طفله). يُغلق إسناده إلى الصفوف، وتُؤرشَف مجموعات الدعم التي يملكها، ويُمسح ربط المدير بمدرسته ونطاق مدير المدارس، ويُلغى اتصال نظام إدارة التعلّم الذي أنشأه (الرموز المخزّنة كانت له). أمّا الخطط والقرارات والاجتماعات والطلبات التي قام بها فتبقى بالمعرّف نفسه، الذي صار يشير إلى حساب بلا هوية يظهر باسم «مستخدم محذوف».
  • ضوابط الأمان. يحدّد الطلب المؤسسة (null لحساب فريق أمل)، وأيّ شخص خارجها يعيد 404. يُرفض الطالب بالرمز 422 PERSONA_MISMATCH مع الإشارة إلى عملية محو الطالب. يُرفض محو حسابك أنت (409 SELF_ACTION_FORBIDDEN) ومحو آخر مسؤول عام نشط (409 LAST_SUPER_ADMIN)، ويتشارك إيقاف الحساب أو حذفه والمحو قفلًا واحدًا لهذا الفحص. محو آخر مسؤول نشط في المؤسسة مسموح، ويُبلَّغ عنه بـlastOrgAdmin: true.
  • سجلّ تدقيق واحد (person_erased) فيه الدور وأعداد الصفوف لكل جدول، ولا يحوي أبدًا القيم الممحوّة. إعادة التنفيذ تعيد alreadyErased: true ولا تغيّر شيئًا.
  • إصلاحات في محو الطالب (صار المحوان يستخدمان قائمة واحدة لما يعرّف الشخص): بقيت تفضيلات واجهة الطالب (خطّ عسر القراءة، التباين) وسجلّ تحديد محاولات الدخول المرتبط باسم المستخدم بعد المحو؛ وصارا يُزالان الآن. وتزيل القائمة المشتركة أيضًا سجلات التسجيل التجريبي والعرض التمهيدي التي تحمل عنوان بريد الشخص.

مراجعة بنية قاعدة البيانات — المرحلة 2: جدول واحد لجلسات الطالب — 2026-09-25

لا عمليات جديدة؛ أشكال الاستجابات كما هي (openapi:check ناجح بلا فرق في المواصفة). الترحيلان 20260926050000_student_session و20260926050100_retire_session_tables.

  • صارت جلسات التشخيص وقوائم التدريب ومجموعات التأكيد جدولاً واحداً هو student_session، فيه حقل kind قيمته diagnostic أو practice أو confirmation، ولكل نوع جدول تفاصيل للحقول الخاصة به. إعادة التشخيص جلسة تشخيص عليها علامة إعادة التشخيص، وليست نوعاً رابعاً، لأنها تمرّ بالمسار نفسه وتخضع لقاعدة «جلسة مفتوحة واحدة لكل نافذة» نفسها. نسخ الترحيل كل جلسة وكل قائمة بمعرّفها نفسه، فتبقى الروابط إليها صالحة؛ وحُذفت الجداول assessment_session وpractice_queue وconfirmation_request.
  • لكل الأنواع قيم الحالة نفسها (active وpaused وcomplete وabandoned) وطابعا البدء والانتهاء نفساهما، وتُخزَّن نافذة التقييم بحالة أحرف واحدة (BOY وMOY وEOY بأحرف كبيرة). طلب التأكيد الذي كان open صار active، وresolved صار complete.
  • صارت لمجموعة التأكيد جلستها. لم يكن لها من قبل صفّ جلسة: كانت الأسئلة المعروضة فيها وإجاباتها تحمل اسم جلسة مصطنعاً (confirm-<رقم>). الآن تشير إلى جلسة التأكيد كأي مسار آخر. وصارت للإجابات والأسئلة المعروضة ونتائج الجلسات ونتائج كتل التدريب ومستلمي جلسات المعلم مفاتيح أجنبية حقيقية إلى الجلسة التي تنتمي إليها، فلا تشير إجابة إلى جلسة غير موجودة.
  • إصلاح: طلبا تأكيد مفتوحان للمهارة نفسها. لم يكن شيء يمنع وجود طلبي تأكيد مفتوحين للطالب والمهارة والنافذة نفسها. صارت قاعدة البيانات لا تسمح إلا بواحد، وصار فتحه متسلسلاً. أبقى الترحيل أحدث الطلبين المكرّرين مفتوحاً وأغلق الأقدم.
  • إصلاح: قاعدة «قائمة تدريب نشطة واحدة» تُطبَّق الآن داخل كل مؤسسة ولا تحسب القوائم المؤرشفة.
  • سجلّ حالات لكل الأنواع. صارت تغييرات حالة قوائم التدريب ومجموعات التأكيد تُسجَّل في جدول سجلّ الحالات، كما كانت جلسات التشخيص تُسجَّل.

مراجعة بنية قاعدة البيانات — المرحلة 2g: الصفوف الدراسية والشُّعب والسنوات الدراسية — 2026-09-25

لا عمليات جديدة، ولا تغيير في شكل الاستجابات (openapi:check بلا فروق). الترحيلات 20260926060000_class_school_year_required و20260926060100_class_id_composite_fks و 20260926060200_student_grade_history_every_change.

  • كل شعبة تنتمي إلى سنة دراسية. صار الحقل Class.schoolYearId إلزاميًا. أعاد الترحيل كتابة التسميات غير المعيارية (“2026/2027” و”2026/27” تصبحان “2026-2027”)، والتسمية التي لا تدلّ على سنة تأخذ السنة الفعّالة للمؤسسة. وأنشأ السنوات الناقصة، وربط كل شعبة بسنة مؤسستها التي تحمل تسميتها. لم يعد ممكنًا أن تختلف تسمية academicYear للشعبة عن تسمية سنتها، ولا أن تشير الشعبة إلى سنة مؤسسة أخرى؛ ترفض قاعدة البيانات الحالتين.
  • إصلاح: تنبيه التراجع الحادّ المفتوح يتبع الطالب الآن. يسجّل التنبيه الشعبة التي أُطلق فيها. وكان استثناء التجميع الذكي وقائمة تنبيهات المعلّم (GET /api/monitoring/alerts) وقائمة «مراجعة فورية» لدى المدير تعتمد على تلك الشعبة لتحديد من يرى التنبيه. فالطالب الذي انتقل إلى شعبة أخرى أثناء تراجع حادّ كان يمكن أن يُجمَع مع زملائه في الشعبة الجديدة (QA_004)، ولم يكن المعلّم الجديد ولا مدير المدرسة الجديدة يريان التنبيه، بينما بقي ظاهرًا لدى السابقين. أصبحت الثلاثة تعتمد الآن على شعبة الطالب الحالية.
  • إصلاح: الترفيع السنوي يرفع كل طالب صفًّا واحدًا انطلاقًا من صفّه هو. قد تضمّ الشعبة طلابًا من أكثر من صفّ (FR-SES-7). كان الترفيع يعطي كل طالب الصفّ التالي للشعبة، فيصبح طالب الصفّ الأول في شعبة الصفّ الثاني في الصفّ الثالث. أصبح هذا الطالب الآن في الصفّ الثاني.
  • يُسجَّل كل تغيير في صفّ الطالب. صفّ الطالب (StudentProfile.gradeLevel) هو صفّه هو، ولا يُستمَدّ من صفّ الشعبة. كان الترفيع وحده يترك أثرًا؛ أمّا الآن فتعديل المعلّم (PATCH /api/students/{id}) وتعديل المسؤول (PATCH /api/users/{id}) وإعادة استيراد قائمة الطلاب أو بيانات نظام إدارة التعلّم التي تستبدل الصفّ، يضيف كلٌّ منها صفًّا في student_grade_history يذكر السبب (correction أو import) ومن أجرى التغيير. تتولّى دالة واحدة كل تغييرات الصفّ، ويرفض فحص جديد (lint:student-grade-single-write-path) أي شيفرة أخرى تكتب الصفّ.
  • معرّفات الشعب في الجداول الأخرى يجب أن تعود إلى المؤسسة نفسها. لم يعد ممكنًا أن تشير التسجيلات وإسناد المعلّمين ومحفّزات المسح ونتائج المجموعات الذكية وأعضاؤها وتنبيهات التراجع الحادّ وطلبات المدير ومسوّدات سير العمل وربط مقرّرات نظام إدارة التعلّم ولقطات لوحة المتصدّرين إلى شعبة من مؤسسة أخرى؛ تفرض قاعدة البيانات ذلك. ويجب أن تكون شعبة عضو المجموعة هي شعبة مجموعته.
  • أُزيل الحقل school_dashboard_snapshot.schoolId. لم يكن يقرؤه أي شيء، وكان يبقى مشيرًا إلى المدرسة القديمة إذا نُقلت الشعبة إلى مدرسة أخرى.

مراجعة بنية قاعدة البيانات — المرحلة 2: إصدارات محتوى الأسئلة — 2026-09-25

لا عمليات جديدة، ولا تغيير في شكل الاستجابات. الترحيلان 20260926040000_item_content و20260926040100_item_content_drop_legacy (P2b).

  • صار لمحتوى السؤال إصدارات. نصّ السؤال وخياراته ومفتاح الإجابة والمشتّتات والوسائط وإعدادات التفاعل وقالب العرض والنصّ القرائي الذي يستخدمه، كلها الآن في item_content، صفّ لكل إصدار لا يتغيّر بعد كتابته. ويبقى في item_bank تصنيف السؤال وحالته ومصدره، ورقم إصداره الحالي. التعديل في «استوديو الأسئلة» يضيف إصدارًا جديدًا ولا يعيد كتابة السؤال في مكانه.
  • العرض يتذكّر الإصدار الذي أظهره. كل عرض لسؤال (إلكتروني أو ورقي) يسجّل رقم إصدار المحتوى (served_task_instance.contentVersion). تُصحَّح الإجابة على ذلك الإصدار، ويرى الطالب في شاشته، والمعلّم في مراجعة الإجابات وفي تصحيح الورقة المطبوعة، ذلك الإصدار نفسه ولو عُدّل السؤال بعد عرضه. في السابق كانت كلها تقرأ أحدث محتوى، فكان تعديل المفتاح أثناء الجلسة (أو بين طباعة الورقة وتصحيحها) قد يجعل الإجابة الصحيحة خاطئة.
  • للنصوص القرائية إصدارات بالطريقة نفسها (passage_content). كل إصدار من السؤال يشير إلى إصدار النصّ الذي كُتب عليه. تعديل النصّ يضيف إصدارًا جديدًا للنصّ وينقل كل سؤال على ذلك النصّ إلى إصدار جديد يشير إليه: العروض الجديدة تُظهر النصّ الجديد، والعروض السابقة تحتفظ بالنصّ الذي عُرض.
  • المعايرة. انتقلت المعايرة الحالية إلى item_calibration_state، ووسوم تحليل الأخطاء إلى item_error_target. صار محرّك التقدير يقرأ لقطات المعايرة المجمّدة عند إصدار المعايرة المثبّت للجلسة، ولا يستخدم لقطة إلا لإجابات إصدار المحتوى الذي قيست عليه. السؤال الذي أُعيدت معايرته بعد التثبيت يُقدَّر الآن بصعوبته المعايَرة السابقة، وكان من قبل يرجع إلى الصعوبة المبدئية. ويستخدم ترتيب أسئلة التدريب المحلِّلَ نفسه، وكان من قبل يأخذ أي صعوبة معايَرة مخزّنة ولو لم تجتز شرط 300 إجابة. ومهمة المعايرة لا تجمع إلا إجابات الإصدار الحالي لكل سؤال، وتسجّل ذلك الإصدار في كل لقطة، وتمسح علامة «المعايرة قديمة» عند إعادة المعايرة.
  • سجلّ تعديلات «استوديو الأسئلة» (GET /api/items/{id}/revisions وGET /api/passages/{id}/revisions) يعيد الحقول نفسها. ويسجّل كل قيد الآن أيضًا إصدار المحتوى الذي أنشأه التعديل، ويحتفظ بالقيم السابقة لحقول التصنيف المعدّلة فقط، لأن إصدار المحتوى السابق يحمل المحتوى القديم كاملًا. وصار PassageDetail.version يعيد إصدار المحتوى الحالي للنصّ.
  • حُذف: 14 عمودًا من item_bank لم يكن أي شيء يقرؤها (requiresInference وdokSmeConfirmed وposTags وlemmas وsamerMaxLevel وcamelsFeatureTags وnearDuplicateOf وrtiSensitive وreportable وsoloSchemaVersion وversion وdeltaSe وinfitMnsq وoutfitMnsq)، وpassages.version.

مراجعة بنية قاعدة البيانات — المرحلة 2 — 2026-09-25

  • نموذج واحد لاستيراد المحتوى (P2d، الترحيلان 20260926020000_content_import و20260926020100_content_import_drop_legacy). كان لاستيراد الأسئلة ولاستيراد مخططات الجلسات مجموعتان منفصلتان من جداول الدفعات وسجلّ الصفوف واعتماد المختصّين؛ وصارتا تتشاركان مجموعة واحدة: content_import_batch وcontent_import_log وcontent_import_approval، مع حقل contentKind قيمته item أو session_blueprint أو passage. نسخ الترحيل كل الصفوف القديمة وأبقى معرّفات الدفعات كما هي، فتبقى الأسئلة والمخططات مرتبطة بالدفعة التي أنشأتها؛ وحُذفت الجداول الستة القديمة. وصارت قاعدة البيانات تفرض قواعد كل نوع: بصمة ملف الدفعة فريدة داخل نوعها (الملف نفسه إذا أُرسل إلى بوابتي استيراد يصبح استيرادين)، ولا يحمل المصدرَ المعلَن وإصدارَ معادلة δ_prior إلا دفعاتُ الأسئلة، ولا يشير كل صفّ في السجلّ إلا إلى صفّ واحد على الأكثر من نوع دفعته، ولا تسجّل كل بوابة إلا أسباب الرفض الخاصة بها. لا تغيير في الواجهة البرمجية: تعيد نقاط استيراد الأسئلة ومخططات الجلسات الاستجابات نفسها؛ ولا ترى كلٌّ منها إلا دفعات نوعها، فمعرّف دفعة من نوع آخر يعيد 404.
  • صار للنصوص دفعة استيراد. النصوص التي تحمّلها سكربتات التعبئة وتجهيز النسخة التجريبية تمرّ الآن بمسار جديد لاستيراد النصوص: دفعة واحدة لكل ملف نصوص، وإعادة استيراد الملف نفسه لا تغيّر شيئًا، والنص الموجود يبقى كما هو، والنص الجديد يسجّل الدفعة التي أنشأته (importBatchId). أما النصوص التي تُكتب يدويًا عبر POST /api/passages فتبقى بلا دفعة كما كانت.
  • المرحلة 2e — محو بيانات طالب. عملية جديدة POST /api/students/{studentId}/erase (الوسم erasure، الملف wp-erasure.yaml). ترحيل 20260926030000_audit_action_student_erased. يستطيع المسؤول العام محو هوية طالب في مكانها عندما تطلب الأسرة ذلك. تُزال الأسماء والبريد الإلكتروني واسم المستخدم والهاتف ومرجع المدرسة وتاريخ الميلاد ورمز الدخول ومفاتيح المرور وربط حساب Google ونظام إدارة التعلّم وروابط وليّ الأمر. وتُحذف من التخزين أوراق القراءة المطبوعة (وملفات الصفّ المضغوطة التي تحتويها) والصفحات الممسوحة وتسجيلات القراءة، وكذلك الإشعارات المتعلّقة بالطفل. أمّا الإجابات والنتائج والأدلّة والقرارات فتبقى بالمعرّف نفسه، وهو يشير الآن إلى سجلّ بلا هوية يظهر باسم «طالب محذوف». يحدّد الطلب المؤسسة (طالب مؤسسة أخرى يعيد 404)، ويأخذ رمز سبب من كتالوج رموز التجاوز (النطاق all؛ لا نصّ حرّ). تكتب العملية سجلّ تدقيق واحدًا فيه أعداد الصفوف لكل جدول، ولا تحفظ القيم الممحوّة أبدًا. تكرار الطلب يعيد alreadyErased: true ولا يغيّر شيئًا. لا يمكن التراجع عنها. دليل التشغيل: docs/runbooks/erasure.md.

مراجعة بنية قاعدة البيانات — المرحلة 2: جدول واحد للإجابات وسجلّ واحد لتقدير القدرة (θ) — 2026-09-25

لا عمليات جديدة، وأشكال الاستجابات لم تتغيّر (أُعيد توليد amal-api.yaml بلا فرق). الترحيلان 20260926010000_item_response و20260926010100_retire_answer_tables.

  • صارت كل إجابة طالب صفًّا واحدًا في item_response أيًّا كان المسار: التشخيص، أو التدريب، أو الورقة، أو التأكيد، أو نقطة المحرّك المستقلة. يذكر الصف مصدر الإجابة (source)، والجلسة أو قائمة التدريب أو الجلسة المولَّدة التي تنتمي إليها، والعرض الذي أجابت عنه (إجابة واحدة على الأكثر لكل عرض). والإجابات التي تعذّر فيها تحميل الصوت أو الصورة تُحفظ لكنها تُعلَّم excluded، ولا يقرؤها أي عدّ ولا تقدير θ ولا معايرة.
  • أُعيدت تسمية diagnostic_session إلى theta_estimate، ويشير كل صف فيه إلى الإجابة التي قدّرها. تُكتب الإجابة وتقديرها في المعاملة نفسها، فلا يوجد تقدير بلا إجابة ولا إجابة مقدَّرة بلا تقديرها. سابقًا كان التدريب يكتب التقدير أولًا ثم الإجابة في معاملة ثانية، فإذا استُبدلت قائمة التدريب بينهما بقي تقدير بلا إجابة.
  • أُلغي: practice_response، وdiagnostic_excluded_submit، وإجابات الورق التي كانت تُخزَّن بصيغة JSON داخل student_task_result (الذي صار يحمل نتائج كتل التدريب فقط). نقل الترحيل الصفوف الموجودة إلى item_response.
  • أعداد كانت خاطئة: كان عدّ تدريب الطالب عند المعلم يحسب الإجابة المكرّرة للسؤال نفسه مرتين، ويعرض إجابات الورق كأنها «كتل» تدريب فارغة؛ وكانت خطة اليوم عند الطالب تحسب السؤال الذي تعذّر تحميله كأنه أُجيب؛ ولم تكن المعايرة تقرأ إجابات الورق، وكانت تقرأ إجابات التدريب التي تعذّر تحميلها. صُحّح كل ذلك.
  • يعيد GET /api/engine/sessions/{id} و…/by-student/{studentId} الحقول نفسها كما كانت؛ وتُقرأ inputResponses وpauseMs وaudioReplayMs الآن من الإجابة المرتبطة.

مراجعة بنية قاعدة البيانات — المرحلة 1C: توحيد سجلّات التدقيق — 2026-09-25

لا عمليات جديدة؛ أشكال الاستجابات لم تتغيّر (حُدّث وصف ثلاث عمليات). ترحيل 20260925050000_audit_consolidation.

  • سجلّ حالات واحد لخمسة كيانات. كان لكلٍّ من تعيينات الملف وتعيينات الحِزم وجلسات التقييم ومستويات التدريب وطلبات المدير نسخته الخاصة من الجدول نفسه: “من حالة، إلى حالة، مَن، لماذا، متى”. صارت كلها تتشارك جدولًا واحدًا لا يقبل التعديل، status_transition، يحميه مُشغِّل منع التعديل في قاعدة البيانات (كانت أحداث طلبات المدير محميّة بفحص الشيفرة فقط). نُسخت كل الصفوف الموجودة. ولا يزال انتقال كل كيان لا يُكتب إلا من كاتبه الخاص (فحص جديد lint:status-transition-single-write-path)، وصار كل انتقال يسجّل الطلب الذي أحدثه.
  • جدول تدقيق واحد لأحداث الفاعلين العامة. قراءات المشرف الأعلى عبر المؤسسات، وتقمّص الشخصيات في النسخة التجريبية، وتغيير قائد المجموعة في الحصة المتزامنة، صارت كلها تُكتب في جدول واحد لا يقبل التعديل، audit_event، بقائمة إجراءات مغلقة وحمولة محدّدة النوع لكل إجراء (فحص جديد lint:audit-event-single-write-path). نُسخت الصفوف الموجودة بمعرّفاتها، فلا تزال روابط سجلّ التدقيق وسجلّ النشاط (bypass:<id> وimp:<id>) تعمل. ويعيد سجلّ التدقيق وسجلّ النشاط ومراقبة النسخ التجريبية الاستجابات نفسها كما كانت.
  • تبقى الجداول ذات العقد الخاص منفصلة: أحداث تسجيل الدخول، وسجلّ اطّلاع المدير على بيانات الطلاب، ومحاولات النص الحرّ المرفوضة (يُخزَّن فيها الطول فقط، لا النص أبدًا)، وقياسات النشاط، وإجراءات المعلم، وعلامات السياق، وتدقيق القرارات، وتنبيهات المنصّة، وتغييرات المعايير، وتغييرات إعدادات إمكانية الوصول.
  • تقسيم شهري لستة جداول أحداث (المرحلة 1C، المجموعة C9، ترحيل 20260925060000_month_partitioning). صارت قياسات النشاط وأحداث تسجيل الدخول ومحاولات تقديم المهام وأحداث الإحماء وسجلّ الاطّلاع على بيانات الطلاب وaudit_event مقسّمة حسب الشهر (قسم لكل شهر بتوقيت UTC إضافةً إلى قسم احتياطي). نُسخت كل الصفوف الموجودة. تبدأ المهمة الليلية (purge:nightly) الآن بـpartitions:ensure التي تُبقي أقسام ثلاثة أشهر قادمة جاهزة، لذا يجب أن تبقى مجدولة؛ ويحذف تنظيف النشاط بعد 90 يومًا الأشهر المنتهية كاملةً بدل حذف الصفوف واحدًا واحدًا. لا يُقسَّم سجلّ أحداث الحصة المتزامنة لأن تسلسل كل حصة يجب أن يبقى فريدًا. لا تغيير في الواجهة البرمجية.

مراجعة بنية قاعدة البيانات — المرحلة 1C: السنوات الدراسية والانتقال إلى السنة التالية — 2026-09-25

عمليتان جديدتان في amal-api.yaml (الوسم tenancy). ترحيل 20260925020000_school_year.

  • صارت السنة الدراسية سجلًّا لا نصًّا حرًّا. لكل مؤسسة سنوات دراسية (school_year: تسمية مثل “2026-2027”، من ١ أيلول إلى ٣١ آب، وحالة: مخطَّطة أو فعّالة أو مغلقة)، ولا تكون في المؤسسة إلا سنة فعّالة واحدة على الأكثر، وتفرض قاعدة البيانات ذلك. يشير كل صفّ إلى سنته، وتبقى تسمية academicYear في الصف مطابقة لها دائمًا. رُبطت الصفوف الموجودة بسنوات أُنشئت من تسمياتها: أحدث تسمية في كل مؤسسة فعّالة، والأقدم مغلقة.
  • صارت كتابة الصفوف تتحقّق من التسمية. يرفض POST /api/classes وPATCH /api/classes/{id} (واستيراد القوائم بملفات CSV) الآن أي تسمية سنتاها غير متتاليتين، مثل “2026-2028”، بالرمز 422. وتحمل استجابات الصف الحقل schoolYearId.
  • جديد: يعرض GET /api/organizations/{orgId}/school-years سنوات المؤسسة من الأحدث إلى الأقدم، مع عدد الصفوف في كل سنة.
  • جديد: ينقل POST /api/organizations/{orgId}/school-years/{yearId}/promote السنة الفعّالة إلى السنة التالية (أو إلى toLabel) دفعة واحدة: تُغلق السنة القديمة وتصبح الجديدة فعّالة؛ ويُنشأ لكل صفّ صفّ في السنة الجديدة أعلى بدرجة في المدرسة والشعبة نفسيهما؛ وينتقل كل طالب مسجَّل برمز الدخول نفسه، ويتقدّم صفّه، ويُسجَّل التغيير في سجلّ جديد للصفوف لا يقبل التعديل. لا يُنقل المعلمون: تبدأ الصفوف الجديدة بلا معلم. ويخرج طلاب الصف الرابع من نطاق الصفوف ١–٤؛ فيُلغى تسجيلهم ولا يُنشأ لهم صف. وتشغيله مرة ثانية للسنة نفسها لا يغيّر شيئًا ويعيد alreadyPromoted: true. يتطلّب صلاحية MANAGE_SCHOOLS؛ ومعرّفات مؤسسة أخرى تعيد 404.

مراجعة بنية قاعدة البيانات — المرحلة 1B: إصدارات الإعدادات — 2026-09-24

لا عمليات جديدة؛ ملف amal-api.yaml لم يتغيّر. ترحيل 20260924130000_config_release.

  • كل كتالوج من كتالوجات الشريك يُجمَّد الآن في إصدار إعدادات. تُعاد تعبئة الكتالوجات من مصنّف الشريك بحسب الرمز الطبيعي، وكان ذلك يكتب فوق القواعد التي حُسبت بها القرارات السابقة. تبقى الجداول الحيّة حاملةً للقواعد الحالية؛ وخطوة نشر جديدة تأخذ لقطة من الكتالوجات الـ٨٨ المسجّلة إلى تاريخ غير قابل للتعديل ومعنوَن بالمحتوى، ولا يحدث ذلك إلا إذا تغيّر شيء فعلًا. الكتالوجات التي لم تتغيّر تتشارك لقطة واحدة عبر الإصدارات، والتراجع عن كتالوج يُنشئ إصدارًا فعّالًا جديدًا يعيد استخدام اللقطة الأقدم.
  • كل صفّ قرار يسجّل الإصدار الذي اتُّخذ القرار في ظلّه. لقطات حالة المهارة والمجال والمجال الكلّي، وتصنيفات الأنماط، وتعيينات الملف، وتوصيات الحِزم وتعييناتها، ونتائج التجميع الذكي، وخطط المتابعة، وتنبيهات القياس والتراجع الحادّ، وتنبيهات الاستجابة للتدخّل، وسجلّات قرار المستوى، وحِزم القرار، كلها تحمل configReleaseId إلزاميًا. تملؤه قاعدة البيانات بالإصدار الفعّال، وترفض الإدراج إن لم يوجد إصدار. الصفوف المكتوبة قبل هذا الترحيل تشير إلى الإصدار ١، وهو خطّ أساس صريح لم يُلتقط محتواه.
  • يشغّل المشغّلون pnpm config:publish مرة بعد نشر هذا الترحيل (وبعد أي تغيير في الكتالوجات خارج التعبئة). التعبئة تنشر تلقائيًا في خطوتها الأخيرة.
  • صار فحص انحراف المخطط يتحقّق أيضًا من وجود كل دالة في قاعدة البيانات يعتمد عليها المخطط.
  • صار محرّك حالة المهارات يقرّر من الإصدار الفعّال لا من الجداول الحيّة (الخطوة 1B-2a). أي تعديل على كتالوج حيّ لم يُنشر لا يستطيع تغيير قرار؛ وكل لقطة مهارة ومجال ومجال كلّي تسجّل الإصدار الذي قرأه المحرّك فعلًا. ومحاكاة المسؤول تقارن القواعد المقترحة بذلك الإصدار.
  • صارت كل مرحلة قرار تقرأ الإصدار الفعّال (المسار أ من الخطوة 1B-2): ملفات الطلاب، وتوصيات الحِزم وتفعيلها، والتجميع الذكي، وسير التفعيل، والمتابعة، وتنبيهات الاستجابة للتدخّل وقرارات المستوى، واتجاهات الطلاقة، وحِزم غرفة البيانات، والأمانة في التنفيذ. وكل صفّ مثبَّت يسجّل الإصدار الذي قرأته المرحلة فعلًا. أما القوائم والتسميات للقراءة فقط فتبقى تعرض الكتالوجات الحالية.
  • أُلغيت أرقام إصدارات الطبقات في محرّك حالة المهارات (المسار ب من الخطوة 1B-2، الترحيل 20260924140000). تغيير في الواجهة البرمجية: صفوف المهارة والمجال والنمط والسلوك التي يعيدها GET /api/sse/students/{id}/* لم تعد تحمل adrRuleVersion وssrRuleVersion وddrRuleVersion وddrLcRuleVersion وpatternDefRuleVersion وrbmRuleVersion؛ ويحمل كل صفّ بدلها configReleaseId، أي الإصدار الذي ضمّ كل طبقات القواعد دفعة واحدة. معرّفات القواعد (أيّ قاعدة انطبقت) لم تتغيّر. وصارت اللقطات مفهرسة ببصمة لكتالوجات المحرّك وحدها، فلا يكرّرها تغيير في كتالوج لا علاقة له، وأي تغيير في قواعد المحرّك ينتج قرارًا جديدًا بدل الإبقاء الصامت على القديم. و«الأحدث» في كل مكان يعني أحدث سنة دراسية، ثم أحدث إصدار، ثم أحدث حساب.
  • أُلغيت أرقام الإصدارات الخمسة في تعيينات ملفات الطلاب (الترحيل 20260924150000). تغيير في الواجهة البرمجية: صفّ الملف الذي يعيده GET /api/profile/{studentId} يحمل configReleaseId بدل profileRuleSetVersion وcdpRuleSetVersion وpgaRuleSetVersion وnarrativeTextSetVersion وaliasSetVersion. وأي تغيير في كتالوج من كتالوجات الملف ينتج ملفًا معلّقًا جديدًا يراجعه المعلم، ولا يفعل ذلك تغيير في كتالوج لا علاقة له.
  • انتقلت توصيات الحِزم والتجميع ومسودات التفعيل إلى الإصدار (الترحيل 20260924160000). صارت التوصيات مفهرسة ببصمة كتالوجات الحِزم الستة؛ وكان أي تعديل على كتالوج حِزم غير خريطة الملف إلى الحزمة يُتجاهَل بصمت للطلاب الذين لديهم توصية. تغيير في الواجهة البرمجية: يعيد POST /api/cluster/recompute/{classId} الحقل configReleaseId بدل ruleSetVersion، وتحمل مسودات سير العمل pinnedClusterConfigReleaseId بدل pinnedClusterRuleSetVersion (وحُدِّث معالج التفعيل لدى المعلم). ولم تعد صفوف توصيات الحِزم وتعييناتها تحمل configVersions وruleVersion.
  • صار التحفيز يثبّت الإصدار (الترحيل 20260924170000). نقاط الخبرة والشارات ومستويات الشخصية والسلاسل تسجّل إصدار الإعدادات الذي قُرئت منه قواعد النقاط وكتالوج الشارات؛ ويحتفظ عكس النقاط عند سحب شارة بإصدار النقاط التي يلغيها، وتُعاد تثبيت الشخصية والسلسلة عند كل تحديث. تغيير في الواجهة البرمجية: يعيد سجلّ التحفيز للمسؤول (GET /api/admin/gamification/audit) الحقل configReleaseId لكل معاملة نقاط بدل ruleSetVersion، ويعرضه جدول السجلّ تحت «إصدار الإعدادات».
  • صارت المتابعة وقرارات المستوى وحزم القرار والتزام التنفيذ تثبّت الإصدار (الترحيل 20260924180000). تُسقط خطط المتابعة ومراجعاتها وسجلّات قرارات المستوى ومسارات حزم القرار وصفوف التزام التنفيذ أعمدة الإصدار الخاصة بكل كتالوج، وتسجّل إصدار الإعدادات بدلها. وصارت عتبات تقييم الالتزام وإعدادات تتبّع الانقطاع جزءًا من كل إصدار، فلا يغيّر تعديلٌ غير منشور عليها أيّ تقييم. تغيير في الواجهة البرمجية: يعيد GET /api/monitoring/status/{bundleAssignmentId} الحقل monitoringPlan.configReleaseId بدل recipeVersion وcriterionVersion، ويعيد GET /api/students/{id}/tier-decisions الحقل configReleaseId بدل movementRuleVersionId.
  • صارت مستويات الدعم والمهام المقدَّمة تثبّت الإصدار (الترحيل 20260924190000). يسجّل تعيين مستوى الدعم للطالب الإصدارَ الذي حُدّد منه مستواه الأول، ويبقى كما هو عند تعديل المعلّم لأنّ المستوى الجديد قرار المعلّم ويُسجَّل في سجلّ الإجراءات. وتنسخ كل مهمة مقدَّمة إصدارَ مستواها (فارغ حين لا يُطبَّق مستوى: المسابير والمهام بلا حزمة والمهام الورقية). تغيير في الواجهة البرمجية: يعيد GET /api/delivery/log/{taskInstanceId} الحقل scaffoldConfigReleaseId بدل scaffoldRuleVersion.
  • صارت سجلّات عرض السرديات ومؤشرات الأنماط الفرعية تثبّت الإصدار (الترحيل 20260924200000). يسجّل كل عرض سردي لكل جمهور الإصدارَ الذي قُرئت منه مجموعة النصوص بدل رقم إصدارها. وصار سلّم الأنماط الفرعية أثناء التدريب يقرأ كتالوجَي أنماط الأخطاء والمشتّتات من الإصدار النشط، فلا يغيّر تعديلٌ غير منشور على نمطٍ ما يُحتسب من أخطاء، وتُعاد تثبيت حالة المؤشر عند كل خطوة محتسبة. لا تغيير في الواجهة البرمجية.
  • صار كل صفّ قرار يسمّي إصداره صراحةً، ولم يعد بإمكان القرارات القراءة من جداول الكتالوج الحيّة (الترحيلان 20260924210000 و20260924220000). لم يعد لعمود configReleaseId قيمة افتراضية في قاعدة البيانات: الكتابة التي تنسى إصدارها تُرفض بدل أن تأخذ الإصدار النشط بصمت. وصارت محمّلات الكتالوج تقرأ من الإصدار النشط افتراضيًّا، ويرفض فحص جديد (lint:config-read-from-release) أي قراءة حيّة للكتالوج خارج العرض والتحقّق والأدوات. وتعديل قواعد اللغة من شاشة المسؤول ينشر إصدارًا الآن، فيسري التعديل فورًا كما كان. تغييرات في الواجهة البرمجية: لم يعد POST /api/assembly/session يقبل assemblyRuleVersion (تُستخدم قواعد الإصدار النشط) وتعيد عمليات التجميع configReleaseId؛ وتعيد تنبيهات الجودة qaConfigReleaseId بدل qaChecksSetVersion؛ ويعيد سجلّ التقديم renderConfigReleaseId للمهام الإلكترونية، ولا يُملأ renderRuleVersion إلا للمهام الورقية.
  • صار الطالب نشطًا في صفّ واحد فقط في آنٍ واحد، وتفرض ذلك قاعدة البيانات (المجموعة C8 من المرحلة 1C، الترحيل 20260925030000). يسمح فهرس فريد جزئي بصفّ ClassStudent نشط واحد لكل طالب، ويتوقّف الترحيل ويذكر الطلاب بأسمائهم إن كان لدى أحدهم تسجيلان نشطان. وصارت الطرق الأربع لإضافة الأشخاص (الإنشاء من المسؤول، والاستيراد من نظام إدارة التعلّم، واستيراد ملفات القوائم، وتعبئة العرض التجريبي) تمرّ بكاتب واحد وقاعدة هوية واحدة: يُطابَق الشخص داخل المؤسسة فقط، ولا يُربط بريد إلكتروني تملكه مؤسسة أخرى أبدًا. تغيير في السلوك: حين يُدرج استيراد نظام إدارة التعلّم طالبًا مسجّلًا تحت صفّ آخر مربوط، يُنقل الطالب (ويُغلق تسجيله القديم كنقل) بدل تسجيله في الصفّين، ويُتجاوز صفّ الاستيراد المربوط بصفّ خارج المؤسسة (ويُحسب في rowsSkipped). لم يتغيّر شكل أي طلب أو استجابة.
  • صارت لوحات مدير المدرسة تقرأ أعدادًا محفوظة للحالات (المرحلة 1C، البند C6، الترحيل 20260925040000_school_dashboard_snapshot). يحفظ جدول جديد، school_dashboard_snapshot، عدد طلاب كل شعبة في كل مجال وحالة وفترة وسنة دراسية. تعيد كتابتَه إعادةُ حساب المجالات الكلية في المعاملة نفسها، ويعيد pnpm dashboard:rebuild بناءه (ويعمل كل ليلة ضمن purge:nightly ليلتقط تغييرات التسجيل)، وقد عبّأه الترحيل بالبيانات الحالية. صارت بطاقات لوحة المدرسة وأعداد التنبيهات فيها، وصفحة التنبيهات، وتاريخ «آخر تقييم» في صفحات الشعب تقرأ هذه الأعداد. قبل ذلك كان كل طلب يطوي تاريخ لقطات كل طالب. الأرقام نفسها، مع استثناء واحد: صفّ السنة الماضية لطالب عائد لم يعد يُحسب بدل فترة هذه السنة. لا تغيير في الواجهة البرمجية.

مراجعة بنية قاعدة البيانات — المرحلة 1A: معرّف واحد للطالب، ومفاتيح أجنبية حقيقية — 2026-09-24

لا عمليات جديدة؛ ملف amal-api.yaml لم يتغيّر. ترحيلات 20260924100000_student_id_unification و20260924110000_student_fks و20260924120000_subskill_fks.

  • صار StudentProfile.id مساويًا لـUser.id بالبناء. كان وجود متسلسلتين عدديتين مستقلتين للطالب الواحد هو الخلل المتكرّر في المنصة: أي انتقال ضائع بينهما يقرأ بيانات طفل آخر بدل أن يفشل. أعاد الترحيل كتابة كل الأعمدة المفهرسة بمعرّف الملف الشخصي إلى معرّف المستخدم (على خطوتين حتى لا يتصادم أي فهرس فريد)، وثبّت مُشغِّلًا قبل الإدراج يُبقي id = userId لكل ملف جديد؛ وأي تعديل يكسر المساواة يُرفض. لم يتغيّر أي عقد في الواجهة البرمجية — كل مسار يقبل الرقم نفسه الذي كان يقبله، وصار الرقم الوحيد.
  • studentId مفتاح أجنبي حقيقي في ٥٣ جدول قياس وقرار، بمنع الحذف، أُضيف بصيغة NOT VALID ثم VALIDATE كي لا يحتاج الإنتاج قفلًا طويلًا. معرّف طالب مختلق أو يتيم يفشل الآن عند الإدراج، ولا يمكن حذف طالب من تحت تاريخه القياسي (المحو يبقى إخفاءً للهوية في المكان).
  • subSkillId/skillId مفتاح أجنبي حقيقي في ٢٥ عمودًا من جداول الأدلة والتقديم والمعايرة إلى كتالوج المهارات، بما فيها الأعمدة القابلة للفراغ. لم يعد ممكنًا كتابة صف دليل لمهارة غير موجودة يتجاهله كل قارئ بصمت.
  • الاختبارات التي كانت تُثبت الانتقال بين الفضاءين صارت تُثبت الثابت الموحّد؛ والبيانات التجريبية ذات المعرّفات المختلقة أُعطيت ملفات حقيقية.

مراجعة بنية قاعدة البيانات — البندان ٩ و١٠: حذف الجداول الميتة، وتقييد مجمّع الاتصالات — 2026-09-23

لا عمليات جديدة؛ ملف amal-api.yaml لم يتغيّر. ترحيل 20260923170000_drop_dead_config_tables.

  • حُذف ٢٠ جدولًا (من ٢٧٥ إلى ٢٥٥ نموذجًا). تسعة عشر جدول إعدادات تعكس أوراق الشريك لم تُملأ يومًا ولم يقرأها أي كود، إضافةً إلى trend_verdict (بلا كاتب ولا قارئ)، وثلاثة تعدادات لا يستعملها سواها، وعمودا تدقيق لم يُكتبا قط، وعرض واحد غير مستعمل. القواعد التي تصفها تلك الأوراق مطبّقة في الكود، والأوراق نفسها تبقى المرجع في docs/product/partner-inputs. لا يعود جدول إلا مع قارئه.
  • حجم مجمّع الاتصالات رقم تختاره العمليات. يُضاف PRISMA_CONNECTION_LIMIT وPRISMA_POOL_TIMEOUT إلى DATABASE_URL لكل نسخة خادم (٤ و٢٠ ثانية على البيئة الرئيسية، ٣ على العرض التوضيحي). ترقية مستوى Cloud SQL وتفعيل تجميع الاتصالات المُدار موثّقان في deploy/cloud-run/DEPLOY.md كخطوتين قبل التوسّع بعد التجريب.

مراجعة بنية قاعدة البيانات — البندان ٧ و٨: قراءة «الأحدث» في قاعدة البيانات، ومهمة التنظيف الدوري — 2026-09-23

لا عمليات جديدة؛ ملف amal-api.yaml لم يتغيّر. ترحيل 20260923160000_current_row_indexes.

  • «الأحدث» يُحسم في SQL. كان تقرير الصف للمعلمة (شبكة المهارات، بطاقات المجالات، منحنيات الاتجاه)، وسلسلة /trends للمدير، وإشارات الحالات للمدير تجلب كل صفوف اللقطات لطلاب الصف ثم تختار الأحدث في الخادم بحسب وقت الحساب. صارت الآن تستخدم DISTINCT ON بقاعدة الحداثة الحتمية — السنة الدراسية الحالية أولًا، ثم نسخة القاعدة، ثم نسخة البذرة، ثم وقت الحساب، ثم المعرّف — على فهارس جديدة، فلا يعود صفّ قديم يتفوّق على إعادة حساب بنسخة قواعد أحدث، ويتناسب حجم البيانات المنقولة مع عدد الطلاب لا مع تاريخهم، وتُشتق سنة الاتجاه من عمود academicYear نفسه.
  • إصلاح مفتاحي ربط بلا فهرس — diagnostic_session.sessionId وClass.schoolId — إضافةً إلى requestId في سجل النشاط.
  • مهمة التنظيف الدوري موجودة. يحذف pnpm auth:purge رموز إعادة التعيين والروابط السحرية المستهلكة أو المنتهية منذ أكثر من ٧ أيام، وتحدّيات مفاتيح المرور، وحالات OAuth، ومعاينات الاستيراد المنتهية، والجلسات غير النشطة منذ ٣٠ يومًا (سجل التدقيق auth_event_log لا يُمسّ)؛ ويجمعها pnpm purge:nightly مع activity:purge. لم يكن أيّ منهما مجدولًا؛ أوامر إنشاء مهمة Cloud Run وجدولتها في deploy/cloud-run/DEPLOY.md ويجب تنفيذها لكل بيئة.

مراجعة بنية قاعدة البيانات — البندان ٥ و٦: منع التعديل على مستوى قاعدة البيانات، وسلسلة القرار بعد التقييم، ومقام نسبة الالتزام — 2026-09-23

لا عمليات جديدة؛ ملف amal-api.yaml لم يتغيّر. ترحيلات 20260923140000_append_only_triggers و20260923150000_planned_cycle_weeks.

  • «الإضافة فقط» صارت تفرضها قاعدة البيانات نفسها لا فاحص المصدر. تعمل الدالة amal_append_only() قبل أي تعديل أو حذف على ٣٩ جدولًا من عمود القياس (أحداث الإتقان، النقاط، لقطات الحالة الثلاث، صفوف الأدلة، سجل θ، الإجابات، درجات القياس المرجعي، سجلات قرارات المستوى، سجل التشغيل، جداول التاريخ، لقطات المعايرة). أي تعديل أو حذف يفشل برسالة append-only: … is forbidden (V-6) — من Prisma أو psql أو خدمة المعايرة أو أي مكان. المخرج الوحيد هو SET LOCAL amal.maintenance = 'on' داخل معاملة (إعادة ضبط العرض التوضيحي، ترحيلات التعبئة لمرة واحدة، قواعد بيانات الاختبار). وصارت بوابة الانحراف تتحقق من وجود المُشغِّلات التسعة والثلاثين بعد كل migrate deploy.
  • إنهاء التقييم يواصل الآن إلى الملف الشخصي وتقييم التنبيهات. بعد وصول اللقطات، يعيد الخادم حساب ملف الطالب لتلك النافذة ويقيّم تنبيهات الطبقة الثانية في نظام الاستجابة للتدخل — وكان كلاهما لا يُستدعى إلا من مُولِّد بيانات العرض التوضيحي، فلم يكن لأي طالب حقيقي ملف، ولم يجد مسار توصية الحزمة ما يقرؤه. توصية الحزمة نفسها تبقى قرار المعلمة.
  • نسبة الالتزام صار لها مقام. يُثبَّت sessionsPlanned وdosageBand في bundle_assignment عند كل تفعيل (فردي، جماعي، عبر سير العمل) من نطاق الجرعة في الكتالوج: الحد الأدنى الأسبوعي («3–5x/week» ← 3) × طول دورة التخطيط (plannedCycleWeeks، افتراضيًا ٦ أسابيع، بانتظار قرار الشريك). قبل ذلك كانت النسبة تُحسب دائمًا على ٠ ← «غير معروف» ← فتُمنع كل ترقية مستوى بقاعدة TM_BLOCK_01.

مراجعة بنية قاعدة البيانات — إصلاحات المرحلة صفر — 2026-09-23

أربعة إصلاحات صحّة نتجت عن المراجعة الكاملة لمخطط قاعدة البيانات (docs/product/db-structure-review-2026-09-23.md). لا عمليات جديدة؛ ملف amal-api.yaml لم يتغيّر. ترحيلات 20260923120000_restore_session_blueprint_tags_gin و20260923130000_snapshot_academic_year.

  • لقطات الحالة صارت مفهرسة بالسنة الدراسية. أُضيف عمود academicYear («2026-2027») إلى مفاتيح skill_status_snapshot وdomain_status_snapshot وmacro_domain_status_snapshot. قبل ذلك كان تقييم بداية السنة الثانية لطالب عائد — بنسخة القواعد نفسها — يصطدم بصفّ السنة الأولى ويُهمَل بوصفه «مكرّرًا» مع سطر سجل فقط، فلا تتحدّث أي حالة. تُستنتج السنة من الصف النشط للطالب، وعُبِّئت الصفوف القديمة بالطريقة نفسها. مسارات القراءة لم تتغيّر.
  • المعايرة لم تعد تحسب التدريب مرّتين. كان مُحمِّل بيانات راش يجمع practice_response مع كل صفوف diagnostic_session، بينما يكتب المحرّك صفًّا في diagnostic_session لكل إجابة تدريب أيضًا. الآن تُقرأ من diagnostic_session الصفوف المرتبطة بجلسة تقييم فقط. كل قيم الصعوبة المنشورة قبل هذا التاريخ حُسبت على بيانات تدريب مكرّرة وستُعاد معايرتها في التشغيل التالي (نسخة جديدة، لا تعديل في المكان).
  • استيراد منصات التعلّم لم يعد يربط مستخدمًا عبر المؤسسات. كانت خطوة الاعتماد تطابق البريد الإلكتروني عالميًا، فيُربط بريد يملكه مستخدم في مؤسسة أخرى بصفوف المؤسسة المستوردة بصمت. المطابقة الآن محصورة بالمؤسسة، ويُتخطّى الصفّ ويُحسب ضمن rowsSkipped.
  • بوابة انحراف المخطط في التكامل المستمر (pnpm db:check-drift). تعمل بعد migrate deploy: يجب أن يطابق schema.prisma الترحيلات المُعادة، ويجب أن تبقى كل كائنات SQL الخام التي لا يستطيع Prisma تمثيلها (٣٢ فهرسًا جزئيًا/GIN، وعرضان، و١٨ قيد CHECK مسجّلة في prisma/raw-sql-objects.json) موجودة. أثناء بنائها تبيّن أن الترحيل 20260624221545 كان قد حذف فعلًا فهرس وسوم قوالب الجلسات في كل البيئات؛ أُعيد وأُعلن في المخطط حتى يتوقف migrate dev عن اقتراح حذفه.

تشغيل إثبات المرحلة التجريبية الأولى على منظومة حقيقية — سبعة عيوب أُصلحت في اليوم نفسه (2026-09-24)

pnpm --filter server seed:pilot-proof ينشئ مستأجر إثبات (مؤسّسة · صفّ أوّل برمز دخول · معلّمة بكلمة مرور · ستّة أطفال برموز سريعة · نافذة منتصف العام مفتوحة اليوم)، ثمّ قُطعت الحلقة كاملة في ثلاثة متصفّحات: المسح → المجموعات التأكيدية الصغيرة → الملف → تأكيد المعلّمة → التوصية → التجميع → التفعيل → بطاقات الحاجة المشتركة. التقرير: docs/superpowers/proof-runs/2026-09-24-pilot1-proof-run.md. أُصلح: (١) تخطّي الإحماء من شاشة البداية كان يحبس الطفل؛ (٢) كلّ قراءة كانت تفترض نافذة بداية العام فيظهر طفل الصفّ الأوّل — ومسحه الأوّل في منتصف العام — «غير مُقيَّم» بملف ناقص البيانات (resolveEvidenceWindow: النافذة المفتوحة اليوم → آخر مسح مكتمل → بداية العام)؛ (٣) لم يكن ثمّة مسار يقود الطفل إلى المجموعة التأكيدية — الإجراء التالي صار confirmation قبل مسح جديد وقبل التدريب، والصفحة الرئيسية تعرض «أسئلة صغيرة للتأكّد»؛ (٤) رابط مباشر لصفحة الطالب كان يعرض «الطالب #id»؛ (٥) كلّ مجموعة تأكيدية كانت تترك صفَّي ملف معلّقين — الحلّ الجديد يُلغي الأقدم؛ (٦) «نقاط القوّة» في بطاقة الخطّة كانت تستعير الجسر المرشَّح للحزمة (الاستماع) — الصفوف تحمل الآن الجسر المدعوم بالبيانات؛ (٧) بطاقة المجموعة تسمّي المهارات المستهدفة الفعلية. مفتوح: OQ-23 (فجوة قاعدة PAC لمهارة PA-07)، OQ-24 (≥ ٦ بنود لكلّ صفّ × مهارة × نطاق)، OQ-25 (فهرس قوالب الجلسات).

النشر الصارم لمخطّط التشخيص في واجهة المشرف، وشارة الخلية المؤقتة، وشاشة تعليم قائمة الكلمات (WP-S0 T0.4 FE + T0.6 FE) — 2026-09-24

محرّر مخطّط التشخيص. زرّ «حفظ» يرسل الآن strict: true، فالمهارة التي يقلّ مخزونها القابل للتقديم عن مسح الأسئلة الثلاثة (أو المهارة غير المفعّلة) تُرفض مع تسمية المهارة — كلّ بند من details[] في استجابة 422 يُعرض بالعربية تحت قائمة المهارات («المفردات السياقية (VOCAB-C03): 2 من 3 أسئلة تقييم للصفّ 1 — أقلّ من حجم المسح.»؛ البند غير المعروف يُعرض بنصّ الخادم كما هو) ولا يُنشر شيء. السكربتات والواجهة البرمجية الافتراضية تبقى متساهلة (warnings[]، صار نوعها معلنًا على PutBlueprintResult). الخلية المزروعة التي تحمل notes: "placeholder — partnerPending OQ-1" تظهر بشارة «قائمة مؤقتة» على الشبكة وبتفسير داخل الحوار (دمج T0.5).

تعليم قائمة الكلمات للمعلّمة. بطاقة رابعة «قائمة الكلمات» في صفحة القياس: كلمات حقيقية (DWR-C01) أو غير حقيقية (DWR-C02) لصفّ الطفل نفسه، والكلمات العشرون شرائح قابلة للنقر (نقرة تعلّم الكلمة المقروءة خطأً؛ لون مرجاني وشطب)، وحقل اختياري للزمن بالثواني، و«تسجيل القائمة» → POST /api/word-lists/assessments بمواضع الكلمات الخاطئة → تُقرأ النتيجة صحيحة من مُحاوَلة مع حالة الإسقاط بلغة النموّ (في النافذة · لا نافذة مفتوحة · سيُعاد). النطاق والنسبة المئوية لا يظهران على سطح المعلّمة أبدًا (V-3). غياب قائمة لـ(الصفّ × المهارة) يُقرأ فجوةَ محتوى («المحتوى بانتظار الشريك»)، ولا تُقدَّم قائمة صفّ آخر. لا تغيير في الواجهة البرمجية.

أداة إعادة التشغيل المقارِنة — والثغرة التي كشفتها في قائمة السماح (WP-S9) — 2026-09-24

pnpm --filter server replay:profiles -- --org <id> --window BOY [--allowlist rows.json] [--required-domains rows.json] [--out file.csv] يحلّ ملف كلّ طالب له لقطات مجال في النافذة بالفهرس الفعّال وبصفوف قائمة السماح / المجالات المطلوبة المقترحة، ويطبع مَن يتغيّر (ملف CSV لكلّ طالب بالمعرّفات فقط + ملخّص توزيع). لا كتابة إطلاقًا بحكم البناء — المحرّك نقي والقارئ للقراءة فقط؛ والاختبارات تؤكّد أنّ عدد التعيينات لم يتغيّر. كشفت أوّل إعادة تشغيل ثغرةً حقيقية: تحت قائمة سماح المرحلة الأولى كان بإمكان صفّ منع التداخل (AO) أن يفرض ملفًّا أساسيًّا خارج القائمة — نمط الدقّة انتخب ACCURACY_GAP عبر AO-02 مع أنّ الصفّ الأوّل لا يقبل إلّا ON_TRACK / MONITORING_PROFILE / FOUNDATIONAL_DECODING_GAP — لأنّ القائمة كانت تصفّي مرشّحي CDP فقط. صار كاسر التعادل لا يقبل إلّا ملفّ قرار مسموحًا (وتبقى مطابقة AO مسجّلة لإعادة التشغيل)، فيتراجع النمط كما يتراجع مرشّح مُصفًّى؛ اختبار انحدار مُثبَت من الأحمر إلى الأخضر. لا تغيير في الواجهة البرمجية.

الجرعة إرشادًا (مستوى الدعم × شريحة الصفّ × مجال المهارة)، وجدولة المعلّمة منفصلة عنها، ومستوى الدعم عند كلّ محاولة تدريب (WP-S8، جولة الشريك الثانية §2.5 + الجولة الرابعة C4؛ مواصفة 2026-09-23 §23–24) — 2026-09-24

الجرعة. نطاقات الشريك الثلاثة صارت صفّ إعداد لا ثوابت: dosage_recommendation (٤ صفوف — المستوى العام × الصفّان ١–٢ × أساسيات القراءة ٢–٥ دقائق × ٤–٥ أسبوعيًّا · العام ٥–١٠ × ٢–٣ · الموجّه ١٠–١٥ × ٣–٤ · المكثّف ٢٠–٣٠ × ٣–٤؛ OQ-11 قابلة للضبط) ويُختار الصفّ الأكثر تحديدًا (مجال المهارة > شريحة الصفّ > أيّ). عند التفعيل يخزّن كاتب التعيين الوحيد الإرشاد المستخلَص في bundle_assignment.recommendedDosage (مع صفّه المصدري لإعادة التشغيل)؛ وجدولة المعلّمة (PATCH /api/assignments/{id}/schedule، OVR_SCHEDULE بسبب من الفهرس) تُحفَظ في scheduledDosage — بالصيغة العددية المغلقة (جلسات/أسبوع · دقائق · مجموع الجلسات) — ولا يُدمج الاثنان أبدًا. صفوف التوصيات تكسب dosageAr («١٠–١٥ دقيقة × ٣–٤ مرّات أسبوعيًّا»، مستخلَصة لكلّ طفل من مستوى الدعم × الصفّ × العائلة) وتغذية متابعة التنفيذ تكسب dosageAr + scheduledDosageAr. واجهة المعلّمة: «الجدولة المقترحة» في بطاقة الخطّة تقرأ الإرشاد؛ وبطاقة التنفيذ في صفحة الخطّة تعرض جدولة المعلّمة أوّلًا و«(الموصى به: …)» بجانبها حين تختلفان. مستوى الدعم عند الإجابة. يسجّل practice_response عند كلّ محاولة scaffoldLevelAtResponse (none · hint:LOW|MID|HIGH · reveal محجوز) وhintCount وindependenceLevel (independent → reduced → supported)، تُستخلَص تحت قفل التدريب من المحاولات السابقة على البند نفسه (الإجابة الخاطئة قدّمت تلميح SOLO)، وصار attemptN يزيد فعلًا عند التصحيح (كان ثابتًا ١). لا شيء يستهلكها لقراءة إتقان في المرحلة الأولى (OQ-20: جمع فقط). T8.3 (مستويات الصعوبة المؤلَّفة ١–٤) تبقى محجوزة على OQ-16 — تبقى سلسلة النطاق هي المستوى. لا عملية جديدة؛ amal-api.yaml يبقى ٣٨٥ مسارًا. الترحيلان 20260925160000_s8_dosage و20260925161000_s8_scaffold_at_response. تحقّقنا في ثلاثة متصفّحات أمام الخادم الوهمي.

الفحص الأعمق للأساسيات — المحفّزان A/B، وموافقة المعلّمة، وجلسة موجَّهة، وقراءة نقطة البدء (WP-S7، جولة الشريك الثانية §1 + §3.3؛ الجولة الرابعة A3/B6/B7/C7) — 2026-09-24

للمرحلة التجريبية الأولى مسارٌ واحد للتقييم الأعمق: الرجوع إلى أساسيات القراءة (الصوت → الحرف والصوت → المقاطع → الكلمة). وحدة جديدة backtrack (٣ عمليات؛ amal-api.yaml صار ٣٨٥ مسارًا). المحفّزات تُقيَّم بعد كلّ إعادة حساب للملف (الخطوة G في جسر التشخيص؛ مقياس القراءة الجهرية يقود السلسلة نفسها) فوق رموز أنتجها المحرّك أصلًا — لا خطًّا رقميًّا أبدًا: A = بلاطة الدقّة والطلاقة دون المستوى/بحاجة مكثّفة مع مؤشّر على فكّ الرموز (نطاق الدقّة دون المتوقّع، أو «دقيق لكن بطيء بوضوح» = نطاق السرعة markedly_below من S4، البديل عن انحرافين معياريين حتى OQ-15؛ قاعدة ٢٥٪ أُلغيت)؛ B = مجال فهم المقروء ضعيف على نحو واسع (coherent_domain_weakness / broad_related_domain_concern، لا مهارة معزولة) مع وصول ليس سليمًا بوضوح. الفهم وحده لا يحفّز؛ و«مجالان دون المستوى» ليست قاعدة. المحفّز يكتب صفًّا واحدًا في backtrack_recommendation لكلّ (طالب، نافذة، سنة دراسية) — ولا يُكرَّر صفّ قائم بأيّ حالة، فقرار المعلّمة يبقى. GET /api/backtrack/students/{studentId} يعيده مع سبب بلغة النموّ والخطوات الأربع (بأسماء المهارات العربية). POST /api/backtrack/{id}/approve (معلّمة الطالب) يفتح جلسة d_triggered الموجَّهة للطفل أوّلًا (قد يرفضها حدّ ١٤ يومًا / حارس الجلسة الواحدة → 409 والصفّ لا يُمسّ)، ثم ينقل recommended → approved → sitting_open بصفّي تاريخ؛ الجلسة تحمل نقاط الفحص الرقمية فقط (قوائم العشرين كلمة يصحّحها المعلّم ولا تُعرض على شاشة)، ويجد الطفل الجلسة في مساره اليومي — كلمة «الرجوع» لا تصل إلى الطالب أبدًا. POST /api/backtrack/{id}/decline {reasonCode} يشترط رمزًا أساسيًّا من الفهرس (applicableScope = all؛ 400 وإلّا) ولا يفتح شيئًا. عند انتهاء الجلسة تقرأ قراءة نقطة البدء نتائج نقاط الفحص الخاصّة بالجلسة (كلّها صحيحة → ضمن المتوقّع · النصف فأكثر → متابعة · وإلّا → ضعيفة؛ أدلّة الرجوع لا تُسقَط على لقطات المسح أبدًا) وتسمّي أوّل خطوة ضعيفة فقط حين قِيست كلّ الخطوات السابقة — وثغرة قبلها تُنتج «تعذّر تحديد نقطة البدء — خطوات غير مقيسة: …» (صدق OQ-3) لا تخمينًا. الإعداد backtrack_sequence (FOUNDATIONAL_READING v1؛ خطوتا الحرف/الصوت والكلمة بانتظار محتوى الشريك، OQ-3)؛ وقت التشغيل backtrack_recommendation (قابل للتعديل عبر كاتب واحد بجدول انتقالات مسموحة) + backtrack_recommendation_history (بالإلحاق فقط، مدرج في الفاحص)؛ مفاتيح أجنبية مقيّدة إلى فهرس الأسباب. الترحيل 20260925150000_s7_backtrack. واجهة المعلّمة: صفحة الطالب تكسب بطاقة الفحص الأعمق للأساسيات — السبب، والخطوات الأربع، والموافقة / عدم الاعتماد (سبب من الفهرس، لا نصّ حرّ)، وحالة الجلسة المفتوحة، وعند الاكتمال سطر القراءة وقراءات الخطوات ونقرة واحدة إلى التدريب على مهارة نقطة البدء. تحقّقنا في ثلاثة متصفّحات أمام الخادم الوهمي؛ وطُبّق تدقيق RTL.

رصد الحاجة المشتركة في الصفّ وبطاقتها (WP-S6، جولة الشريك الثانية §1 + مواصفة المطوّر 2026-09-23 §25–26) — 2026-09-24

الدعم على مستوى الصفّ كلّه هدفُ تعيين لا كيانَ خطّة، لذا صار ملخّص الصفّ يقول أين توجد حاجة مشتركة. GET /api/reports/classes/{id}/class-summary (وملخّص مجموعة الدعم) يحمل classWideNeeds {skillNeeds[], domainConcerns[], thresholds} للجمهورين — أعداد ونسب من الطلاب فقط، لا درجة ولا هويّة طالب. حاجة مهارة تظهر حين يكون ≥ ٤٠٪ من الطلاب الذين قِيسوا على المهارة نفسها ضعافًا (الضعاف ÷ المقيسون؛ طفل قيد المراجعة أو do_not_decide_yet خارج العدّين — صفوف perSkill تحمل الآن doNotDecideYetCount؛ وطفل الدعم المكثّف داخلهما، OQ-4) وهي قابلة للتنفيذ: تحمل عبارة المهارة المستهدفة (focusAr من skill_focus_phrase) وpriority — high لمهارة بوّابة في الصفّين الأوّل والثاني (وزن للترتيب لا تجاوزًا). قلق مجال يظهر حين يكون ≥ ٥٠٪ من المقيسين على بلاطة كلّية دون المستوى/بحاجة مكثّفة وهو إخباري (actionable: false) مع مهارات البلاطة التي تُراجَع أوّلًا — قاعدة الشريك «افحص المهارات أوّلًا»؛ لا يُقترح تدخّل على مستوى المجال أبدًا. «الضعف» هو مجموعة الحالات التي يوجّهها موجِّه التدريب إلى التدريب العلاجي (practice_experience_map) فلا يختلف الرصد عن بذر التدريب. العتبات صفّ إعداد (class_need_threshold: skillShare 0.40 · domainShare 0.50 · gatewayBoostGrades [1,2] · countIntensiveInDenominator true؛ رقم الإصدار يعود في الاستجابة). واجهة المعلّمة: لوحة الصفّ تعرض بطاقة الحاجة المشتركة — «{النسبة}٪ من الصفّ يحتاج دعمًا في: {المهارة المستهدفة}» بنقرة واحدة إلى مركز الجلسات مصفًّى بتلك المهارة (?subSkillId=) و«عرض الطلاب»؛ وقلق المجال يعدّد المهارات التي تُراجَع من دون زرّ تعيين؛ والبطاقة بلا أسماء وتختفي حين لا شيء يُقال. خرج من فحص المتصفّح حارسان: مركز الجلسات يستخلص الاسم العربي لمهارة مرتبطة من خارج قائمة صفّ الفصل، وSelect المشترك يعرض عنصره النائب — لا الرمز الخام — لقيمة بلا خيار مطابق. لا عملية جديدة؛ amal-api.yaml يبقى ٣٨٢ مسارًا / ٥٧ شريحة. الترحيل 20260925140000_s6_class_need_threshold. تحقّقنا في ثلاثة متصفّحات أمام الخادم الوهمي.

طبقة المعلّمة: ست عائلات دعم، وسطر المهارة المستهدفة، ومستوى دعم ظاهر، وبطاقة الخطّة، ومراجعة بسؤال واحد، والتقديم نطاقًا × وسيطًا (WP-S5، جولة الشريك الثانية §2 + مواصفة المطوّر 2026-09-23 §4–6 / §11.3 / §17) — 2026-09-24

صارت المعلّمة تقرّر من سطر واحد لكلّ طفل — «المجال» (إحدى عائلات الدعم الستّ، بالنصّ نفسه على البلاطة والتقرير) و**«المهارة المستهدفة»** (عبارة المهارة المستهدفة) و**«مستوى الدعم»** (دعم عام / دعم موجّه / دعم مكثّف — تراكمي، منفصل عن حالة الأداء؛ ولا يظهر «المستوى ١/٢/٣» أبدًا) — بدل اسم حزمة ورمز مستوى. صفوف GET /api/workflow/recommendations/{classId} تحمل الآن familyNameAr وfocusAr وsupportLevelAr. خانة «المرساة» في التوصية تحمل محدِّد الحزمة (D-006..009)، لذا تُستخلَص المهارة المستهدفة من أضعف حالة للطفل نفسه داخل العائلة المعروضة (bundle/engine/target-skill.ts؛ حتمي: الشدّة ثم معرّف المهارة)؛ وخطّة القراءة الجهرية تحدّد هدفها من ملف المقياسين — الدقّة / السرعة / كلاهما (المواصفة §11.3) — لا من عبارة مهارة واحدة. GET /api/students/{id}/tier يحمل supportLevelAr (الخادم يملك النصوص الثلاثة في rti/support-level.ts؛ الواجهة تعكسها واختبار في كلّ جهة يؤكّد تطابقها؛ ورقاقات المدير تقرأ الكلمات نفسها). GET /api/profile/{id} يحمل oralReadingProfile (on_track · accuracy_need · rate_need · accuracy_and_rate_need · insufficient — مقياس واحد سليم لا يدّعي «على المسار»، GSR-05) + oralReadingProfileAr + oralReadingFocusAr. GET /api/bundles/{id}/definition يحمل family {familyId, nameAr, successStatementAr} — سؤال بطاقة المراجعة الوحيد. إعداد عامّ جديد: bundle_family (٦ صفوف — خريطة 18→6؛ الخطّة العابرة للمجالات تعرض عائلة مجال مهارتها المرساة، ولا عائلة سابعة) وskill_focus_phrase (٨٠ صفًّا فعّالًا = ٢٥ عبارة من الشريك + عبارتا القراءة الجهرية من مواصفة المطوّر على FL-C01 / FL-D01 بانتظار OQ-22 + ٥٣ بديلًا من التصنيف؛ الدفعات اللاحقة عبر pnpm --filter server import:focus-phrases --file <json> [--dry-run] الذي يرفض مصطلحًا محظورًا أو عبارة تتجاوز ستّ كلمات؛ وتبقى COMP-A03/A05/C09 على البديل، OQ-2). التقديم صار نطاقًا × وسيطًا فوق خيارات التقديم التسعة (bundle/engine/delivery-axes.ts، يفشل مغلقًا عند معرّف غير مُخرَّط؛ ويعود الزوج إلى الخيار المخزَّن ضمن المجموعة المتوافقة مع الحزمة). واجهة المعلّمة: لوحة التوصيات تصفّي بالعائلة وتُعنوِن بالأسطر الثلاثة (اسم الحزمة تفصيل تحت السبب)؛ صفحة الطالب تفرد سطرًا لمستوى الدعم؛ مراجعة التفعيل تعرض بطاقة الخطّة (نقاط القوّة · الحاجة الحالية · العائلة + المهارة المستهدفة · الأنشطة · النطاق · الوسيط · مستوى الدعم · الجدولة · المتابعة) وتبقي الوصفة الداخلية — الحزمة والمرساة والخيوط الداعمة والجسر وتوزيع الجرعة وسلسلة القواعد — خلف «التفاصيل» وخارج الصفحة افتراضيًّا؛ صفحة الخطّة تكسب بطاقة المراجعة (عبارة نجاح العائلة؛ حكم المحرّك يختار مسبقًا نعم / جزئيًا / لا؛ التغيير يحتاج سببًا من الفهرس؛ do_not_decide_yet لا يؤكَّد؛ وacute_regression يقفلها)؛ ومجال الاستماع غير المفعَّل يُعرض «غير مُقيَّم في هذه المرحلة» على كلّ الواجهات، ولا يُعرض نتيجةً أبدًا حتى مع وجود صفّ. لا عملية جديدة؛ amal-api.yaml يبقى ٣٨٢ مسارًا / ٥٧ شريحة. الترحيلان 20260925120000_s5_bundle_family و20260925130000_s5_skill_focus_phrase. تحقّقنا في ثلاثة متصفّحات (المدمج، Playwright، Chrome DevTools) أمام الخادم الوهمي؛ وطُبّق تدقيق RTL (أرقام مشرقية للمدى، ومطابقة عربية للعدد، وتهجئة واحدة لـ«موجّه»).

قوائم الكلمات العشرين المصحَّحة من المعلّم تدخل المحرّك مقياسَ مجموعة بنود (WP-S0 T0.6، مواصفة الشريك 2026-09-23 §9) — 2026-09-23

مقياسا الكلمات الحقيقية (DWR-C01) والكلمات الزائفة (DWR-C02) في المسح الشامل هما قائمتان من عشرين كلمة يقرؤها الطفل جهرًا ويصحّحها المعلّم، لا ثلاثة أسئلة رقمية — وكان المحرّك يطوي أي نتيجة متعدّدة البنود إلى نمط n/3 (18 من 20 = ٩٠٪ كانت تُقرأ «2/3» أي حدّية وتفتح فحصًا تأكيديًا). وحدة جديدة word-list-measure: GET /api/word-lists (قوائم الصفّ) و**POST /api/word-lists/assessments** (مجموعة الكلمات المقروءة خطأ → صحيح / محاوَل / نسبة → نطاق قياسًا إلى توقّع الصفّ → صفّ أدلّة screening_score واحد بـvalue.kind = ITEM_SET_MEASURE → السلسلة نفسها التي يسلكها التقييم: المهارة → مجال DWR → المجال الكلّي → الملف). جلسة الطفل الرقمية صارت تتخطّى المهارات المصحَّحة من المعلّم الواردة في خليّة المخطّط (تبقى في الخليّة، فيُقرأ المجال «جزئيًا» حتى يسجّل المعلّم القائمة)، ولم يعد نشر المخطّط يشترط لها مخزونًا رقميًا. لا تُقدَّم قائمة إلا لصفّ الطفل نفسه (٤٢٢)؛ وقائمة مفقودة ثغرة محتوى (٤٠٤)؛ ولا نافذة مفتوحة → تُسجَّل ولا تُسقَط. النطاقان ٩٠ / ٧٥ بديل هندسي حتى تصل نقاط قطع الشريك (OQ-19)؛ كل صفّ يحمل standIn. إعداد word_list_measure_config (صفّان)؛ محتوى word_list (على الشريك)؛ وقت التشغيل word_list_assessment (بالإلحاق فقط، سنة دراسية، مفاتيح أجنبية حقيقية — درسا مراجعة قاعدة البيانات ١ / ٩). المحرّك: رموز نطاق set_* + ADR-SET-01..03 + PAC-SET-01؛ تعداد النطاقات صار مشتركًا (MeasureBand). عمليتان جديدتان؛ amal-api.yaml صار ٣٨٢ مسارًا / ٥٧ شريحة. الترحيل 20260925110000_s0_6_word_list_measures (ونُقل ترحيل S4 إلى 20260925100000 ليتأخّرا عن ترحيلات فرع مراجعة قاعدة البيانات — ملاحظات التوفيق في docs/superpowers/seams/db-review-sync-2026-09-23.md).

القراءة الجهرية تدخل محرّك حالة المهارة (WP-S4، جولة الشريك الرابعة B5/B6) — 2026-09-23

عند إنهاء جلسة قراءة جهرية (POST /api/orf/assessments/{id}/stop) يُسقَط الآن مقياسان — دقّة القراءة وطلاقة/سرعة القراءة — كلٌّ منهما حالةَ مهارة مستقلّة، لا يُجمعان بمتوسّط ولا يُحوَّلان إلى نمط n/3. يُصنَّف كل مقياس في نطاق قياسًا إلى معيار الصفّ (expected · below_expected · markedly_below) ويُكتب صفَّ أدلّة oral_reading_benchmark_probe على مهارته الحاملة (الدقّة → FL-C01، السرعة → FL-D01)، ثم يسلك السلسلة نفسها التي يسلكها التقييم التشخيصي: لقطات المهارة → مجال FL_ACC مرّة واحدة (قراءة التركيبات الأربع: كلاهما ضمن المدى → مناسب؛ مقياس واحد دون المتوقَّع → هو محلّ الاهتمام؛ كلاهما دون المتوقَّع → الأسرة كلّها؛ أيّ مقياس دون المتوقَّع بوضوح → قلق تقوده مهارة بوّابة) → مربّع المجال الكلّي → الملف (بانتظار مراجعة المعلّم). حتى وصول جدول معايير الشريك (OQ-15) يقوم حكم المعيار المزروع وعتبتا الدقّة ٩٥ / ٩٠ مقامَ النطاقات — إعداد عامّ orf_measure_band_rule (٧ صفوف) تُثبَّت نسخته على كل صفّ. Not_Assessed (لا معيار، نافذة غير منطبقة، جلسة غير مربوطة) لا يكتب شيئًا؛ وإعادة القياس في النافذة نفسها تَجُبّ السابق (لقطات المهارة تكتسب basisRevision، بالإلحاق فقط). تكتسب استجابة الإنهاء projection {written, window, accuracyBand, rateBand, skippedReason}؛ وما يراه المعلّم يبقى الكلمات الصحيحة في الدقيقة. خطآن أُصلحا: صفوف المعيار الفلسطينية (ORF_WITH_DIACRITICS) كانت غير قابلة للوصول — فكل حكم فلسطيني كان Not_Assessed؛ وgradeBand يُشتقّ الآن من ملف الطالب حين يغفله العميل (صفحة القراءة الجهرية لا ترسله)، على مسار البدء ومسار القياس. تغيير سياسة: صار Accuracy_Fluency مجالًا مطلوبًا للصفوف ٢–٤ — ملف طالب في هذه الصفوف بلا نتيجة قراءة جهرية في النافذة يكون DATA_INCOMPLETE. لا عملية جديدة؛ amal-api.yaml يبقى ٣٨٠ مسارًا / ٥٦ شريحة. الترحيل 20260923130000_s4_orf_measure_bands. المحرّك: ٣ صفوف ADR-ORF + صفّ PAC-ORF + صفّا DDR-FL؛ وصار تمرير المجال المؤجَّل يحمل نمطًا مشتقًّا (كانت DDR-04/05/06/07 غير قابلة للوصول من التقييم التشخيصي).

طلبات التواصل بدل التسجيل التجريبي (التقاط طلبات الموقع) — 2026-09-23

نماذج «اطلب عرضاً» في الموقع التسويقي (نافذة الرأس/البطل، و/signup، و/summit، ومفاهيم الصفحة الرئيسية) صارت ترسل إلى POST /api/contact-requests — مجهول الهوية، خلف Turnstile، ومحدود المعدّل (٥ لكل IP في الساعة، ٣ لكل بريد؛ يُحفظ IP كتجزئة مملّحة فقط). لا يُزوَّد أي شيء: يُخزَّن الطلب في contact_request أولًا، ثم يصل إشعار إلى بريد الفريق (CONTACT_INBOX، وإلا عنوان MAIL_FROM، وإلا SMTP_USER) وتأكيد عربي أولًا إلى صاحب الطلب — وفشل البريد يُسجَّل ولا يُعرض للعميل. GET /api/admin/contact-requests (المشرف الأعلى الحقيقي) يعرض أحدث الطلبات. عمليتان جديدتان؛ amal-api.yaml صار ٣٨٠ مسارًا / ٥٦ شريحة. ترحيل 20260923120000_contact_requests. على العميل صار المسار: نموذج → «استلمنا طلبك» (بلا استطلاع حالة ولا كشف بيانات دخول)، وأُزيل lib/demo-site.ts وفروع النشر الثاني، وأُعيدت تسمية المكوّنات إلى contact-request/*.

سحب بيئة العرض التجريبية (WP-S10) — 2026-09-23

أُزيل منتج العرض التجريبي الذاتي بالكامل: وحدتا demo وdemo-admin (التسجيل، التزويد، بوّابة الموافقة، مسح الانتهاء، انتحال الشخصيات، المراقبة)، وشخصية DEMO_ADMIN ودورها ذو الـ١٦ صلاحية، ووسائط الحماية الخاصة بالبيئة التجريبية على كل مسار كانت عليه، وحقل impersonatedBy في GET /api/auth/me، ومصدر impersonation في سجل النشاط، وأكواد الخطأ DEMO_*، ورسائل الترحيب واستلام الطلب، وseed:demo، ونشر app-demo المنفصل (خدمة Cloud Run، خدمات compose، مضيفات Caddy، قاعدة growamal_demo). حُذفت ١٢ عملية؛ amal-api.yaml صار ٣٧٨ مسارًا / ٥٥ شريحة. الترحيل 20260923110000_s10_retire_demo_tenant يحذف جداول العرض التجريبي وعمود session.impersonatedByUserId وorganization.isDemo وصفّ الدور وقيمة التعداد DEMO_ADMIN — ويرفض التنفيذ ما دامت صفوف تجريبية موجودة: يُشغَّل أولًا pnpm --filter server purge:demo-tenants --confirm (تجربة جافة افتراضيًا) على كل قاعدة بيانات. على العميل أُزيلت /demo و/demo-login و/demo-admin و/admin/demo-tenants وشريط الانتحال وخصائص demoMode وملف تعريف الارتباط amal_demo. نماذج «اطلب عرضًا» في الموقع التسويقي ما زالت ترسل إلى /api/demo/register المحذوف — وهي القرار التالي (التقاط طلبات التواصل أو الإزالة).

تبسيط المرحلة التجريبية الأولى (WP-S0 · S1 · S2): إعداد اليوم الأول، وبوّابات المحرّك، وإغلاق سلسلة التقييم → الملف → الدعم — 2026-09-23

كل ما تحتاجه المدرسة الأولى لمسار «تقييم → حالة المهارة → ملف مبسّط → دعم»، مبنيًّا بحيث يُفعَّل نموذج V5 الكامل لاحقًا بالإعداد لا بالبرمجة. عملية واحدة جديدة؛ المجموع ٣٩٣ مسارًا / ٤٢٨ عملية. ترحيلات: 20260922100000_s1_coverage_basis، 20260922101000_s1_required_domains_by_grade، 20260922102000_s1_pilot_profile_allowlist، 20260922103000_s2_snapshot_basis_revision.

  • إعداد اليوم الأول (S0). pnpm seed:pilot-config ينشر نوافذ التقييم الثلاث ومخطّط الصف الأول (١١ مهارة وعي صوتي × BOY/MOY/EOY) على مستوى المؤسّسة. PUT /api/admin/diagnostic-blueprint صار يرفض المهارة غير المفعّلة (422) ويُبلّغ عن ضعف بنك الأسئلة في warnings[] مع الاستجابة 200 — أو 422 عندما يحمل الطلب strict: true.
  • التغطية نسبةً إلى المخطّط (S1). كان مقام «تغطية المجال» كل مهارات المجال النشطة، فيبقى طفل الصف الأول «جزئيًّا» إلى الأبد. الآن هو خليّة المخطّط المنشورة لصفّه ونافذته (مدرسة → مؤسّسة → عام)، ثم نطاق الصف، ثم المجال كاملًا؛ ويُحفَظ الاختيار في domain_status_snapshot.coverageBasis.
  • المجالات المطلوبة حسب الصف + قائمة ملفّات المرحلة الأولى (S1). جدولا إعداد عامّان (required_domain_by_grade، pilot_profile_allowlist). مجال مطلوب غائب هذه النافذة يوقف الملف عند «بيانات غير مكتملة» (كان يمرّ بصمت كـ«على المسار»). المرحلة الأولى تُظهر فقط: على المسار · متابعة · فجوة أساسيات فكّ الشيفرة (+ معدِّلان)؛ وغياب صفّ في الجدول يعني فتحًا كاملًا، فيبقى محرّك V5 كاملًا قابلًا للوصول ومختبَرًا.
  • إغلاق السلسلة (S2). بعد انتهاء التقييم: المهارات → كل مجال متأثّر مرة واحدة بعد استقرار كل المهارات الشقيقة (كان صفّ المجال يتجمّد عند تغطية المهارة الأولى ١/ن) → المجال الكلي → recomputeProfile (بانتظار مراجعة المعلّمة). تأكيد الملف عبر review-resolution يُحتسب بعده recommendBundle ويعيد bundle {written, bundleId, objectType, actionCode, idempotent}. مسار جديد POST /api/profile/{studentId}/recompute لإعادة الحساب يدويًا (مقيّد بمعلّمة الصف).
  • مراجعات أساس اللقطة (S2). domain_status_snapshot وmacro_domain_status_snapshot يكتسبان basisRevision ضمن المفتاح الفريد. حين تتغيّر مجموعة اللقطات المغذّية عند نسخة القواعد نفسها — مجموعة تأكيدية تحسم مهارة بوّابية موقوفة — يُلحِق الكاتب مراجعة جديدة بدل تجاهلها، ويبقى الصف الأقدم تاريخًا (B.7). ثم يُعاد حساب الملف بعد اكتمال المجموعة التأكيدية، فتنتقل الطالبة من «بيانات غير مكتملة» إلى «فجوة أساسيات» دون خطوة يدوية.
  • خلايا «لا تقييم» الصريحة (T0.5، الجولة 4 A1 — الصف الأول لا يجلس لتقييم بداية العام). PUT /api/admin/diagnostic-blueprint/{grade}/{cycle} يقبل الآن subSkillIds: [] كخلية صريحة تعني «لا تقييم شامل لهذا الصف في هذه النافذة». GET /api/student/today-plan يكتسب screeningState: "not_screened": تُتخطّى النافذة المفتوحة بهدوء لهذا الصف (تعرض الصفحة الرئيسية «لا يوجد تقييم مفتوح الآن»، لا «لا توجد أسئلة جاهزة»)، ولا يُطلق أي تنبيه نقص محتوى. الخلية المفقودة لم تتغيّر — تبقى على مسار QA_040 الصاخب حتى لا تُقرأ خلية منسيّة على أنها قرار. seed:pilot-config ينشر خلية BOY الفارغة للصف الأول دائمًا، أمّا قائمتا MOY/EOY المؤقتتان فلا تُنشران إلا لمؤسّسة تجريبية أو مع --allow-placeholder.
  • التدريب من المهارات المُقاسة (WP-S3، الجولة 4 B3/B4). صار بذر التدريب موجِّهًا من الحالة إلى نوع التجربة (remedial · reinforcement · maintenance · enrichment · collect_evidence) عبر جدول إعداد عام جديد practice_experience_map — الطالب على المسار يحصل على قائمة تثبيت/إثراء بدل الرفض، وضعف المهارة البوّابية يتقدّم، وdo_not_decide_yet لا يولّد شيئًا. practice_queue.experienceType يسجّل ما فتحته المهارة المحورية. التقديم على مستوى الصف فقط في كل مكان (القياس والتدريب وعدّ بنك المخطّط): لا رجوع إلى صف آخر — مهارة مؤهّلة بلا عنصر تدريب في صف الطالب تُطلق الفحص الجديد QA_041 (سجل تنبيهات المنصة، مرة واحدة لكل صف × مهارة يوميًا؛ السجل صار ٤١ فحصًا) وينتقل البذر إلى المهارة المؤهّلة التالية في الصف نفسه. جلسة يوزّعها المعلّم تحلّ محلّ قائمة التدريب المبذورة من التقييم (supersededByQueueId) بدل تخطّيها؛ جلسة معلّم فوق جلسة معلّم تبقى تخطّيًا. تقديم التدريب يجري تحت حزمة الدعم الفعّالة عند وجود صف مستوى سقالة للمهارة، وبلا مستوى خلاف ذلك. ترحيل 20260923100000_s3_practice_experience_map. لا تغيير في المسارات.
  • الثوابت. لا نموذج لغوي في أي خطوة قياس (V-5)؛ لا نسبة مئوية واحدة للطالب (V-3)؛ جداول القياس تُلحَق فقط (B.7)؛ المعلّمة تقرّر في النقطة نفسها (V-12).

تجربة المدير (WP-MGR) الشريحة BE-4: نموذج الاجتماع، وملخص الصف، وتصدير قائمة الطلاب، والكتالوجان المنتظران من الشريك — 2026-09-19

المستندات التي يُدار بها اجتماع مراجعة البيانات فعليًا، مع عقود الكتالوجات للمحتوى الذي ما زال على الشريك. ٦ عمليات جديدة؛ المجموع ٣٩٢ مسارًا. لا ترحيل قاعدة بيانات — كل جدول تكتب فيه هذه الشريحة وصل في BE-0 وBE-3.

  • GET /api/principal/students/{studentId}/meeting-form.pdf يطبع «نموذج مناقشة الحالات الطلابية» معبّأً ببيانات الطالب على مستوى الحالة: المجالات الخمسة، ومهارات المجال المحدّد، وخطة الدعم النشطة، وآخر نتائج المتابعة، والطلبات المفتوحة — ثم مساحات مسطّرة فارغة. المناقشة والقرارات تُكتب على الورق ولا تعود إلى المنصة: لا يوجد حقل نص حر في هذه الواجهة لاستقبالها، والنموذج الورقي هو ما يغني عنه.
  • GET /api/principal/classes/{classId}/summary.pdf صفحة «حالة الصف» في ورقة واحدة: معلومات الصف، وبطاقة النمط الأبرز، وجدول المهارات بتوزيعه الكامل، وأسئلة المناقشة. تجميعي فقط — لا يذكر اسم أي طالب.
  • GET /api/principal/classes/{classId}/students/export يصدّر الصفوف نفسها التي يعرضها الجدول بالمرشّح نفسه، بصيغة CSV (بترميز UTF-8 مع علامة BOM حتى لا تظهر الأسماء العربية مشوّهة في Excel) أو PDF أفقي. يستدعي الدالة نفسها التي تبني الشاشة، لا استعلامًا ثانيًا. وفوق الحدّ الأقصى (٥٠٠ صفًّا افتراضيًا) يُطلب تضييق المرشّح مع ذكر الرقمين — ولا تُقتطع القائمة بصمت أبدًا.
  • GET /api/principal/classes/{classId}/discussion-prompts يقرأ «أسئلة للمناقشة» من كتالوج مغلق يؤلّفه الشريك، مفهرس بـ(المجال × نوع النمط). لا تُولَّد آليًا إطلاقًا. الكتالوج يصل فارغًا بانتظار Q-MGR-10، فتعيد الخدمة قائمة فارغة وتعرض الواجهة «قريبًا» — وهذا هو العقد، لا خطأ.
  • GET /api/principal/meeting-templates يسرد النماذج الأربعة الثابتة ويتيح تنزيلها (Q-MGR-9). يُفحص وجود الملف على القرص عند كل طلب، فيكفي وضع الملفات ليتحوّل الكارت إلى تنزيل حقيقي دون تعديل برمجي؛ وحتى ذلك الحين تُعرض جميعها بحالة «قريبًا». ولا يُسجَّل أي سجل اطلاع لهما — فالنموذج الفارغ لا يذكر طالبًا، بينما النموذج نفسه معبّأً يُسجِّل سجلًّا واحدًا.
  • سياسة النسب على الورق. كل نسبة مطبوعة تحمل عدديها: «١٢ من ٢٣ (٥٢٪)»، وإذا لم يُقيَّم أحد تُطبع «—» لا «٠٪» — فـ«لم يُقَس أحد» و«لم يبلغ أحد المستوى» ليسا الشيء نفسه.
  • توسيع فحص المصطلحات الدولية (Q15) ليغطي واجهات المدير وكلا مولّدَي ملفات PDF بعد أن كان محصورًا بوحدة واحدة.
  • بيانات العرض التوضيحي. أصبح seed:demo يملأ واجهة المدير: أربع شعب دراسية بصفّين لكل منها، وقائمتا غرفة البيانات، ومجموعتا دعم، ومعلمة نشطة وأخرى غير نشطة، واجتماع قادم بجدول أعماله واجتماع سابق، وطلب لكل حالة، والحالات الحديّة التي يجب أن تثبتها الشاشات.

تجربة مدير المدرسة (WP-MGR) الشرائح BE-1 · BE-2 · BE-3 · FE-2 · FE-7: الشاشات التجميعية الخمس، وقراءات مستوى الطالب، وطلبات المدير واجتماعاته، ولوحة البدائل، 2026-09-19

بقية إعادة تصميم تجربة مدير المدرسة فوق أساس BE-0/FE-0/FE-1 أدناه. ٢٨ عملية جديدة. أصبح amal-api.yaml ٣٨٦ مسارًا / ٤٢١ عملية (من ٣٥٩ / ٣٩٢ على main). الترحيلان 20260918124000_wp_mgr_be_meetings_and_requests و20260919120000_wp_mgr_be_student_visibility.

  • BE-1 — القراءات التجميعية. أربعة عشر مسارًا خلف شاشات المدير: طيّات الشعبة والصف وفئة الدعم، وإشارات الانتباه، وطوابير غرفة البيانات، ومؤشرات استخدام المنصة، والبحث ضمن النطاق. كل نسبة تحمل الأعداد التي حُسبت منها وتسمّي مقامها؛ والعدد الذي لم يُقَس يُبلَّغ عنه بـnull لا بـ0.
  • BE-2 — قراءات مستوى الطالب (القرار D-1). ثمانية مسارات مُدقَّقة تضع اسم الطالب وحالته أمام المشرف لأول مرة، إضافةً إلى الأجزاء الخاصة بالطلاب من البحث وقائمة الانتباه وطوابير غرفة البيانات. شكل الاستجابة قائمة سماح مبنية صراحةً لا طرحًا من شكل أوسع: θ والخطأ المعياري وδ_prior وإجابات الأسئلة وصفوف الأدلة وتفاصيل حزمة القرار ومستوى السقالة الفردي ونقاط التحفيز وتاريخ الميلاد وبيانات ولي الأمر ورمز الدخول كلها غائبة بحكم البناء. يُكتب سجل StudentDataAccessLog واحد لكل استجابة على مستوى الطالب، قبل إرسالها؛ والطلب خارج النطاق يُعيد 404 دون كتابة أي سجل. وOrganization.studentLevelVisibility مفتاح إيقاف، مفعَّل افتراضيًا.
  • BE-3 — أول عمليات كتابة للمدير. رمز صلاحية سادس وعشرون (CREATE_PRINCIPAL_REQUEST)، وجدول principal_request مع سجل حالاته غير القابل للتعديل، واجتماعات مراجعة البيانات بلقطة جدول أعمال مجمَّدة، وثلاثة أنواع إشعارات، ووصلة تفتح مراجعة المستوى داخليًا. لا يمسّ أي مسار للمدير جدول student_tier_status — فتغيير المستوى طلب لا كتابة (B.20).
  • FE-2 — الشاشات التجميعية الخمس. لوحة المدرسة، ولوحة الشعبة، والنصف العلوي من لوحة الصف، ومجموعات الدعم، واستخدام المنصة، بتخطيط الشريك وألوانه.
  • FE-7 — لوحة البدائل. أربع معالجات لمدرسة تجريبية واحدة على /principal/storyboard/* لمراجعة الشريك. بيانات تجريبية فقط؛ لا يُقرأ أي مسار وكل أدوات الإجراء معطّلة.

تجربة مدير المدرسة (WP-MGR) الشرائح BE-0 · FE-0 · FE-1: وحدة principal-views ولوحة المدرسة المجمَّعة، وسجلّ الوصول إلى بيانات الطلاب، وإعدادات المدرسة المُصدَّرة، وشريط الشريك الجانبي وترويسته، وبوّابة النسب المئوية، 2026-09-18

خادم + هيكل واجهة مدير المدرسة ومدير المدارس. الشرائح الثلاث الأولى من إعادة تصميم تجربة المدير (المتطلّبات prds-v2/40-teacher-experience/45-manager-experience-redesign.md؛ التصميم docs/design/wp-mgr-be/ + docs/design/wp-mgr-fe/). لا شاشة ذات محتوى لمدير المدرسة بعد: BE-0 قراءة الأساس، وFE-0 مكوّنات العرض وفحوصه، وFE-1 الهيكل. عملية جديدة واحدة. يبلغ amal-api.yaml الآن 360 مسارًا / 393 عملية. الترحيلات 20260918120000_wp_mgr_be_config_and_catalog و20260918122000_wp_mgr_be_access_log و20260918123000_wp_mgr_be_read_indexes.

  • GET /api/principal/schools/{schoolId}/dashboard (principalSchoolDashboard، الوسم principal-views؛ VIEW_SCHOOL / VIEW_ORG / RUN_BACKOFFICE) هو طيّ مجمَّع واحد للمدرسة لكل (schoolId, window, period)، يُطوى في الذاكرة من مجموعة قراءة واحدة: لا حلقة على الصفوف، وحارس عدد الاستعلامات أدناه يثبت ذلك. يحمل المتن المجالات الكبرى الخمسة للموجة الأولى، ولكل منها counts على ستّ فئات عرض (meets وapproaching وbelow وsevere وunder_review وnot_assessed) وmeetsShare وband الخاصّة بالمجال (الأسوأ يغلب)؛ وenrolledCount / assessedCount؛ ومؤشّرات الاستخدام الثلاثة المختصرة (teachersActive وstudentsActive وplansOnPlan مع periodFrom / periodTo وpartialPeriod)؛ وحكم كفاية البيانات dataSufficiency (sufficient وweeksElapsed وrequiredWeeks وstudentCoverage وblockingReasons)؛ وattention (أعداد لكل عائلة تنبيه، وهو [] حتى BE-1)؛ وqueueCounts (null حتى BE-1 ومفتاح dataRoomOverviewStrip)؛ وwave2Tiles (يظهر فقط مع showWave2Tiles). الاستعلام: window (BOY | MOY | EOY؛ إغفاله = نافذة المدرسة الحالية من تقويم التقييم) وperiod (this_month | last_30_days | last_90_days، بسقف أفق القياس البالغ 90 يومًا). Cache-Control: private, max-age=60. لا يخرج أيّ معرّف طالب من هذه الاستجابة، فلا تكتب صفًّا في سجلّ الوصول.
  • غلاف meta على كل استجابة من الوحدة: { assessmentWindow, computedAt, ruleVersion, configVersion, stale, languageRuleSetVersion }. يُشتقّ stale من حداثة البيانات (أحدث لقطة مساهمة أقدم من snapshotStaleMinutes، افتراضيًّا 60) لا من ساعة تحديث؛ وإذا لم يوجد صفّ مساهم أصلًا فـstale: true مع computedAt عند لحظة الطلب. يُثبَّت ruleVersion (قواعد الطيّ) وconfigVersion (العتبات؛ 0 = الافتراضيات في الشيفرة) منفصلَين ليميّز الاسترجاع بين «تغيّرت القواعد» و«أعادت المدرسة ضبط مفتاح» (V-6). وlanguageRuleSetVersion هو null في القراءات المجمَّعة.
  • شكل Share هو النسبة المئوية الوحيدة على واجهة المدير: { numerator, denominator, value, shareOf }، وvalue في [0, 1] و**null كلّما كان المقام 0** (يُعرض «—» لا 0%)؛ وshareOf ∈ assessed_students | enrolled_students | measured_skills | active_plans | active_teachers | enrolled_students_active. تُعرض Not_Assessed وPartial وContextual فئاتٍ مستقلّة وتُستبعد من كل مقام، ولا تُطوى في 0 أبدًا. ولا حقل «مستوى قرائي عامّ» في أيّ موضع من الاستجابة (V-3).
  • الأخطاء، اقرأ هذا قبل الربط. 403 هو بوّابة الصلاحية فقط. كل نتيجة نطاق هي 404: المدرسة من مؤسسة أخرى، أو مدرسة أخرى، أو خارج scopedSchoolIds لمدير المدارس، أو غير الموجودة أصلًا، كلها متطابقة على السلك (عدم الإفصاح عن الوجود)، ولا يكتب 404 صفًّا في السجلّ. لا تقرأ 403 بمعنى «موجود لكن ممنوع» على أيّ مسار /api/principal/**. و422 لقيمة window / period غير صالحة.
  • ثلاثة جداول جديدة. student_data_access_log هو سجلّ التدقيق خلف القرار D-1 (يرى مدير المدرسة أسماء الطلاب وحالاتهم للقراءة فقط): صفّ واحد لكل استجابة HTTP على مستوى الطالب (كشف من 25 صفًّا = صفّ واحد بـsubjectStudentCount = 25؛ وتبديل التبويب طلب مستقلّ فصفّ مستقلّ)، يُكتب قبل إرسال الاستجابة (تعذُّر الكتابة يُسقط الطلب، فلا يُقدَّم متن على مستوى الطالب بلا تدقيق أبدًا)؛ وsubjectStudentUserId هو User.id؛ وfilters مجموعة مفاتيح مغلقة ويُرفض المفتاح المجهول؛ ولا يُخزَّن نصّ البحث أبدًا بل queryLength فقط؛ ويربط requestId الصفّ بأثر الطلب. إضافة فقط بفحص CI (lint:no-update-on-audit-tables) ومسار كتابة واحد (lint:principal-views-single-write-path ← repository/access-log-writer.ts)، وهو فحص واصطلاح لا ضمانة من قاعدة البيانات. تشحن BE-0 الكاتب وتختبره؛ أمّا مسارات الطالب التي تستدعيه فتصل في BE-2. school_literacy_index_config يحمل عتبات واجهة المدير، 17 مفتاحًا (minimumWeeks وstudentCoverageThreshold وgaugeBandCuts وclassConcernShare وclassMinAssessed وclassPacketCount وdataIncompleteDays وpartialVerdictStreak وusageInactiveDays وgroupSlowShare وminComparablePoints وsnapshotStaleMinutes وexportMaxRows وpersistQueueSnapshots وshowWave2Tiles وdataRoomOverviewStrip وprivacyFooterKey)، نشر ثم تجميد: التعديل يُدرج version + 1 ويعطّل الصفّ السابق، وفهرس فريد جزئي يضمن صفًّا نشطًا واحدًا بالضبط لكل (organizationId, schoolId)؛ والحلّ: صفّ المدرسة ← صفّ المؤسسة ← افتراضيات الشيفرة التي تعيد إنتاج PRN_CONFIG المُثبَّت سابقًا بايتًا ببايت، فـconfigVersion = 0 يعني «سلوك لم يتغيّر». ينشئ البذر صفًّا افتراضيًّا نشطًا واحدًا على مستوى المؤسسة لكل مؤسسة ليس لها صفّ. كل عتبة مملوكة للشريك (Q-MGR-4 / Q-MGR-5)؛ والافتراضيات هي قيم العمل الواردة في المتطلّبات. discussion_prompt_catalog إعداد عامّ يؤلّفه الشريك، نشر ثم تجميد، بصفر صفوف في الموجة الأولى (Q-MGR-10)؛ يثبّت البذر العدد عند 0 فيصير تسليم الشريك تغييرًا مرئيًّا مقصودًا؛ وتعرض الواجهة «قريبًا» ولا يُولَّد شيء (V-5).
  • تصحيحات تصميم تستحقّ انتباه المُدمِج. جدول runtime_audit_log المذكور في المتطلّبات غير موجود: runtime_audit_row هو عمود القرار (بلا عمود studentId) وليس سجلّ التدقيق؛ السجلّ هو student_data_access_log. والعرض school_dashboard_snapshot الذي تسمّيه 44 FR-PRN-11 لم يُبنَ قطّ ولا يُبنى هنا: يطوي R0 عمود macro_domain_status_snapshot الحيّ عبر فهرس تغطية جزئي جديد واحد (DISTINCT ON والعرض المادّي هما سلّم التصعيد المقيس، الموجة الثانية). وجملة «403 لخارج النطاق» في 44 مُعدَّلة إلى قاعدة 404 أعلاه. ويبقى lib/scope.ts::resolveStudentScope مجمَّدًا (يُرجع forbidden لمدير المدرسة، ويعتمد عليه 29 موضع كتابة)؛ أمّا resolveSupervisorStudentScope المحلّي في الوحدة فيفوّض القرار إلى canReachStudent المشحون، ويفرض lint:principal-scope-isolation هذا الحدّ.
  • CI. وظيفة جديدة wp-mgr-be بخدمة Postgres 16 خاصّة بها تشغّل ثلاث خطوات حاجبة: lint:mgr (مسار الكتابة الواحد · عزل النطاق · مُنشئ Share، حيث يرفض lint:principal-share-constructor أيّ نسبة خام خارج engine/shares.ts · جداول التدقيق إضافة فقط · معرّف الطلب على جداول النشاط · مسار الكتابة الواحد لحالة المستوى · لا نموذج لغويّ، مع إضافة principal-views إلى المجموعة التي يغطّيها ذلك الفحص)، وحارس عدد الاستعلامات لكل مسار (test:mgr:query-count: عدد استعلامات R0، المثبَّت عند 21، يجب أن يتطابق على تركيبة من 4 صفوف وأخرى من 30، لأنّ N+1 سريعًا على تركيبة صغيرة يبدو أخضر لفحص زمن الاستجابة)، وحزمة اختبارات الوحدة (test:principal-views). وأُلحقت الأوامر الثلاثة نفسها بـtest:qa. قيس عند خروج BE-0 على تركيبة من 750 طالبًا (منصّة PERF=1 عند الطلب، ليست في CI): p95 لـR0 هو 202 مللي ثانية مقابل بوّابة 2000 مللي ثانية.
  • ثغرات معروفة. attention هو [] وqueueCounts هو null حتى تشحن BE-1 عائلات التنبيه ومحرّك الطوابير (تُحذف العائلة ذات العدد صفر بموجب العقد، فـ«لم يُبنَ بعد» و«لا يُطلق» يُعرضان سواء). يتلقّى DEMO_ADMIN الردّ 404 على R0 (لا فرع لـDEMO_ADMIN في canReachSchool المشحون: إغلاق آمن، مثبَّت باختبار، ويُحلّ مع بذر العرض التجريبي في BE-4)، فلا يمكن لمستأجر العرض إظهار اللوحة الجديدة بعد. ولا تسرد صفحة تدقيق المشرف وصولَ مدير المدرسة بعد (BE-4). وما زال pnpm test:tenant-isolation ليس خطوة في CI؛ يصير خطوة حاجبة قبل دمج BE-2.
  • الواجهة، المكوّنات والفحوص (FE-0). ShareValue (components/viz/share-value.tsx) هو المكوّن الوحيد الذي يطبع % على واجهة مدير المدرسة أو مدير المدارس: يُصدر data-share-of="<numerator>/<denominator>" (أو data-rate-of="<key>" لرقم بلا زوج أعداد، كتنفيذ الخطط) مع عبارة مخفيّة بصريًّا «n من d …»، ويعرض «—» بلا سمة لمقام صفري. يعمل فحصان جديدان داخل pnpm --filter web lint الذي تشغّله وظيفة build: lint:no-global-percentage (قائم على شجرة الشيفرة: يحكم على مواضع النصّ المعروض ونداءات مُنسِّقات النسب، لا قيم CSS ولا عامل باقي القسمة ولا التعليقات؛ ومخرج الطوارئ // eslint-percent-allow: <reason>) وlint:no-inline-arabic (يجب أن يأتي أيّ نصّ عربيّ داخل شجرة المدير من lib/manager-copy.ts أو lib/status-display.ts أو lib/arabic-count.ts؛ والملفّات السابقة في خطّ أساس مؤرَّخ). الوكيل الجذري pnpm test:render:no-global-percentage. وتحلّ مفردات D-5 على مستوى المنصّة كلّها في status-display.ts: صارت رقاقة Approaching تقرأ «تحت المتابعة» وLISTEN_COMP يقرأ «الفهم المسموع» (بما في ذلك واجهات المعلّمة).
  • الواجهة، الهيكل (FE-1). الشريط الجانبي لمدير المدرسة هو ستّة الشريك + ثلاثة: /principal · /principal/grades · /principal/students · /principal/support-groups · /principal/usage · /principal/data-room، ثم «الإعدادات» · «مركز المساعدة» · «تسجيل الخروج» (والأخير صفّ تنقّل جديد من نوع kind: "action" يفتح حوار الحساب بدل رابط) وكتلة شعار واحدة. ويحتفظ شريط مدير المدارس بـ«لوحة المؤسسة» (/manager) ويضيف اختصارات بنطاق المدرسة على /manager/orgs/:orgId/schools/:schoolId/{grades,students,support-groups,usage} (تُحلّ من المسار أو من آخر مدرسة زارها) إضافة إلى /manager/data-room على مستوى المؤسسة. تعرض الترويسة على كل شاشة لمدير المدرسة أو مدير المدارس المدرسةَ + العام الدراسي، والبحث المحدود بالنطاق (يُرسَل بتأخير قصير إلى GET /api/principal/search، وهو مسار من BE-1، فيتراجع اليوم إلى «البحث غير متاح حاليًا.»)، والجرس بعدد غير المقروء، ورقاقة المستخدم بسهم القائمة؛ وتحمل الصفحات تحت الرئيسية مسار تنقّل بأيقونة الرئيسية، ورابط رجوع حيث يرسمه التصميم. و/principal/implementation ← /principal/usage#implementation و/principal/review ← /principal/data-room تحويلان 307 من next.config.ts (مع حفظ الاستعلام، لإصدار واحد)؛ ويحتفظ /principal/growth و/principal/leaderboard بصفحتيهما ويغادران الشريط الجانبي فقط (D-8). تعرض اثنتا عشرة صفحة لمدير المدرسة وخمس لمدير المدارس عنصرًا نائبًا صريحًا «قيد الإنشاء — يصل مع الشريحة التالية» بالعنوان الحقيقي ومسار التنقّل؛ وتبقى صفحة /principal الرئيسية هي اللوحة الحالية حتى تعرض FE-2 تخطيط الشريك على R0. وتعرض الصفحة خارج النطاق بطاقة 404 («هذه الصفحة غير متاحة ضمن نطاقك»)، لا 403 أبدًا.

راجع مدير المدرسة ومدير المؤسسة للشاشات الحالية، والمنسقون والمدراء للأدوار والنطاقات، ومرجع الواجهة البرمجية لأشكال MgrSchoolDashboard وMgrShare وMgrMeta الكاملة.

إدارة المستخدمين للمسؤول: مراجعة متدرّجة، وعمليات كاملة، وإعادة تعيين كلمة المرور مع الإرسال بالبريد، 2026-09-16 (مُوفَّق؛ صدر أصلًا في 2026-09-07)

صار amal-api.yaml يضمّ 352 مسارًا و385 عملية.

أُعيدت صياغة هذا القيد ليصف الواجهة بعد توفيق تصميم 2026-09-07 مع #138 (“استقبال أول عميل”، 2026-09-09). السجلّ المرجعي: docs/superpowers/specs/2026-09-16-admin-user-management-reconciliation.md.

  • GET /api/users (listUsers) تصفية متدرّجة: بالمؤسسة (لمشرف المنصّة فقط)، فالمدرسة، فالدور، فالصفّ، فالحالة، فالبحث، مع ترقيم بالإزاحة وحقل total.
  • GET /api/users/{id} و**PATCH /api/users/{id}** (getUser / patchUser) صارا شكلًا واحدًا مدموجًا. تحمل التفاصيل والتحرير معًا حقول الهويّة من #138: أجزاء الاسم العربي الأربعة التي يركّبها الخادم اسمًا كاملًا (fullNameAr)، إضافة إلى البريد الإلكتروني (وهو معرّف دخول البالغ) والهاتف واسم المستخدم، إلى جانب الحالة (إيقاف/إعادة تفعيل) وحقل خاصّ بدور المستخدم: نقل صفّ للطالب، أو استبدال صفوف المعلّمة وربطها بمدرسة، أو إعادة تعيين مدرسة لمدير المدرسة، أو نطاق مدارس للمشرف، أو مقعد اختصاصي للمسؤول.
  • DELETE /api/users/{id} (deleteUser) حذف ناعم: تُنهى الجلسات والرموز، ويجري تسلسل الإلغاء حسب الدور، ويُعلَّم البريد الإلكتروني كمحذوف داخليًّا فيمكن إعادة استخدامه، ولا يمكن أبدًا إزالة آخر مسؤول عام نشط.
  • POST /api/users/{id}/password/reset (resetUserPassword) هو إجراء الضبط أو إعادة التعيين لكلّ مستخدم على حدة: توليد بيانات دخول أو كتابتها يدويًّا، مع كشف لمرّة واحدة وإرسال اختياري إلى العنوان المسجّل أو عنوان آخر. بيانات دخول الطالب رمز واحد من 4 أرقام، هو نفسه رمز دخول الصفّ وكلمة مرور المنزل، فإعادة تعيينه تُدوِّر الاثنين معًا.
  • الإرسال الجماعي لم يتغيّر ويبقى POST /api/users/credentials/send الخاصّ بـ #138: يختار المسؤول عدّة حسابات فيرسل إليها بيانات الدخول، تلقائيًّا (إعادة إرسال للطلاب، وإعادة تعيين للبالغين) أو بإعادة تعيين للجميع. يتعايش مساران للإرسال بقصد: إجراء الصفّ هو إعادة التعيين الفردية أعلاه، وإجراء الشريط العلوي هو هذا الإرسال الجماعي.
  • يحمل AuthEventLog الآن actorUserId وحقل auditMeta بمفاتيح مغلقة في كلّ كتابة بمبادرة من مسؤول، إلى جانب حقل detail الخاصّ بـ #138. سبعة أنواع أحداث تعود لهذا التوفيق (admin_password_reset وcredential_email_failed وuser_created وuser_updated وuser_suspended وuser_reactivated وuser_deleted)؛ أمّا credential_emailed فمن #138 ويحمل الآن actorUserId أيضًا.

راجع مرجع الواجهة البرمجية لأشكال الطلب والاستجابة الكاملة.

مركز جلسات المعلّمة: قائمة واحدة لكل أنواع الجلسات، وكشوف الإنجاز، ومراجعة إجابات كل طفل، وإعادة الإرسال، وكشف للطباعة، 2026-09-11

خادم + معلّمة. كانت المعلّمة تنشئ جلساتها وتتابعها في أربعة أماكن منفصلة، ولا مكان منها يجيب عن سؤال «من أنهى؟ وبماذا أجاب كل طفل؟». صارت /teacher/sessions قائمة واحدة تغطّي صفوفها كلّها بأربعة تبويبات (تدريب = جلسة مولَّدة، تقييم = تقييم صفّ أو إعادة قياس واحدة، قراءة = دفعة قراءة مخطّطة، حصّة مباشرة = حصّة مباشرة)، ويفتح كل صفّ كشفًا. وكل ما يُعرض كان محفوظًا أصلًا، فلا جدول جديد ولا ترحيل. 7 عمليات جديدة. يبلغ amal-api.yaml الآن 355 مسارًا / 386 عملية (بعد دمج إصدار تفصيل أخطاء القراءة).

  • GET /api/teacher/sessions?kind=training|screening|reading|live&classId&cursor&limit يُرجع نوعًا واحدًا في كل نداء، من الأحدث إلى الأقدم، بمؤشّر صفحات مبهم (createdAt, id) وكتلة أعداد لكل صفحة { total, completed, inProgress, notStarted, other }. وهي أعداد لا نسب مئوية. وإغفال classId يعني كل صفوف المستدعية؛ أمّا صفّ لا تدرّسه فيردّ 403. وتحمل الحصّة المباشرة الجارية counts: null، لأنّ تفصيل كل طالب لا يوجد إلّا بعد انتهائها. ومؤشّر لم تُصدره هذه النقطة يردّ 400 بدل العودة الصامتة إلى الصفحة الأولى.
  • GET /api/sessions/{id}/progress هو كشف المستلمين لجلسة مولَّدة مُسلَّمة: completed أو in_progress أو not_started أو stopped أو skipped أو excluded، مع itemsAnswered وitemsCorrect وitemsTotal وlastActivityAt. وتُشتقّ الصفوف الرقمية من قائمة التمرين ومن سجلّ الإجابات الذي لا يُعدَّل (تفوز المحاولة الأخيرة لكل سؤال، والصفّ الذي أخفق في تحميل وسائطه ليس إجابة)، وتُشتقّ الصفوف الورقية ممّا أدخلته المعلّمة من علامات. و409 قبل التسليم، و404 خارج مؤسسة المستدعية.
  • GET /api/sessions/{id}/recipients/{studentId}/responses يُرجع إجابات طفل واحد سؤالًا سؤالًا: نصّ السؤال والخيارات وما اختاره وما هو المفتاح ونوع الخطأ المخزَّن. ويعود المختار والصحيح قوائمَ من معرّفات الخيارات (chosenOptionIds وcorrectOptionIds) محلولةً عبر مطابقة الخيارات التي صحّحت الإجابة نفسها، فيحمل السؤال متعدّد الاختيار أو المرتَّب كل قيمه، وتصل الإجابة القديمة المخزَّنة بنصّ الخيار إلى المعرّف نفسه. ويقول orderSensitive إنّ الترتيب هو المهارة. ويُعلّم reviewable: false أنواع التفاعل التي تُصحَّح بمفتاح على الخادم (الإملاء الكتابي، ودمج البطاقات، وتقطيع المقاطع، والفراغات متعدّدة المواضع، وترتيب الكلمات)، فتعرضها الواجهة بعبارة «لا يمكن مراجعتها هنا» بدل صفّ فارغ.
  • GET /api/classes/{classId}/screening-triggers/{id}/progress يقابل القائمة النشطة للصفّ بالجلسات التي فُتحت تحت تقييم واحد. وتفوز آخر جلسة لكل طفل، ويُستثنى الطفل الذي ترك الصفّ من الكشف ومن أعداد التبويب معًا. وcompletedAt هو وقت إنهاء الجلسة فقط، ولا يُستعاض عنه بوقت البدء أبدًا.
  • POST /api/sessions/{id}/resend (المتن { studentIds }، حتى 200) يعيد تسليم جلسة مُسلَّمة لمستلمين مُسمَّين عبر المسار نفسه الذي سلّم أوّل مرّة. ويعود كل معرّف مطلوب في سلّة واحدة بالضبط: queued، أو stillBlocked (ما زال لدى الطفل تدريب آخر مفتوح)، أو alreadyWaiting (يحمل هذه الجلسة أصلًا)، أو notResendable (قائمة منتهية أو متروكة، أو معرّف ليس مستلمًا مؤهَّلًا، أو نسخة ورقية بلا ملف بعد). ويستعيد المستلمون الورقيون ملفّهم القائم لإعادة التنزيل، دون إعادة توليد أي شيء. والعملية مُكرَّرة الأثر، وليست تجاوزًا: تعيد محاولة التسليم ولا تغيّر قرارًا.
  • GET /api/sessions/{id}/progress.pdf و**GET /api/classes/{classId}/screening-triggers/{id}/progress.pdf** يطبعان الكشف (A4 من اليمين إلى اليسار: الاسم، وكلمة الحالة، والصحيح/الكلّ). والخلايا على سطر واحد، فيتبع عدد الصفحات عددَ الصفوف، وما تجاوز 500 كيلوبايت يردّ 503 بدل متن بلا حدّ.
  • وأيضًا: تحمل صفوف GET /api/reading-assessments/batches/{id} الآن wcpm وaccuracy إلى جانب administeredAt الموجود أصلًا. ويبقى كلاهما فارغًا حتى تُوقَف القراءة وتُصحَّح، فالصفّ الذي أُجريت قراءته ولم تُوقَف بعدُ يبقى فارغًا. ويكتسب سجلّ جلسات الطفل نوعًا جديدًا هو generated، أي جلسة طبعتها له معلّمته؛ ولا تُدرَج الجلسة الرقمية مرّتين لأنّها تظهر أصلًا بوصفها تدريبًا.
  • صفحات المعلّمة: مركز الجلسات بتبويبات الأنواع ورقائق الصفوف، وكشوف تفصيل التقييم والقراءة والحصّة المباشرة، وكشف إنجاز على الجلسة المُسلَّمة (تصفية، واختيار من لم يُكمل، وإعادة إرسال، وطباعة)، ومراجعة إجابات لكل طفل تُعلّم ما اختاره والخيار الصحيح جنبًا إلى جنب. أعداد فقط، ولغة نموّ في كل مكان: «توقّف مؤقتًا» للجلسة المتوقّفة، و«لديه تدريب جارٍ» لمن كان لديه تدريب مفتوح.

خطوط الهدف حسب النمط، وحارس أهليّة القياس، وصفحة «لم نجد هذه الصفحة» بالعربية، 2026-09-11

خادم + واجهة. خمس متابعات من مراجعة «تفصيل». لا عملية جديدة؛ يبقى amal-api.yaml عند 348 مسارًا / 379 عملية. الترحيل 20260911120000_orf_sub_skill_and_aim_line_cbm_type.

  • صار aim_line لكلّ نمط قياس — المفتاح (الطالب، المهارة، cbmType، الإصدار). كان منحنى التقدّم لكلّ نمط بينما خطّ الهدف المقارَن به ليس كذلك، والتفعيل للأسبق، فكانت ثلاث قياسات دقّة (نسبة مئوية) قد تُنشئ الأساس الذي يقرؤه منحنى الكلمات في الدقيقة هدفًا له، فيبقى ذلك المنحنى دون الهدف دائمًا. تُملأ الصفوف القائمة من نمط مجموعة الأساس الخاصّة بها. ويقبل POST /api/cbm/aim-lines الآن cbmType (افتراضيًّا ORF_WCPM).
  • لا يُسجَّل قياس طلاقة إلّا تحت مهارة مؤهَّلة للقياس (صفوف FL-ACC الأربعة، skills_master_table.cbmEligible). يردّ POST /api/orf/assessments/start وPOST /api/cbm/probes بـ400 cbm_skill_not_eligible فيما عدا ذلك. قبل هذا كان رابط مُركَّب يدويًّا يسجّل قياس قراءة جهرية تحت مهارة فهم، فيدخل بصمت في تجميع طلاقة المدرسة ويزيح الوسيط. ولا يتأثّر القياس غير المرتبط (subSkillId: null).
  • صار oral_reading_assessment.subSkillId عمودًا حقيقيًّا — كان يعيش داخل benchmarkValuesSnapshot.__subSkillId فقط، غير مرئيّ لـSQL ولا لأيّ قارئ سوى معالج الإنهاء. مُلئ بأثر رجعيّ، ويبقى التثبيت في اللقطة قراءةً احتياطيّة للجلسات الأقدم.
  • صفحات «لم نجد هذه الصفحة» بالعربية للجذر ولواجهة الكبار ولعالم الطالب. كانت كلّ مواضع notFound() الـ63 تسقط إلى صفحة Next الإنجليزية المدمجة.
  • إتاحة النوافذ على سفاري/WebKit — تُصيَّر حرّاس تركيز Base UI هناك كأوامر ARIA بلا اسم (مخالفة aria-command-name في كلّ نافذة مفتوحة)، ولأنّ WebKit لا يُركّز الزرّ عند اللمس كان إغلاق النافذة يعيد التركيز إلى أوّل عنصر في الصفحة بدل الزرّ الذي فتحها. أُصلح الأمران في المكوّن المشترك، فاستفادت مواضع النوافذ الخمسون كلّها.

تفصيل الخطأ في كلمة: أيّ حرف أو حركة قُرئت خطأً، 2026-09-09

خادم + معلّمة. أثناء تسجيل قياس القراءة الجهرية تفتح المعلّمة «تفصيل» على كلمة مميَّزة وتختار الحرف أو الحركة التي أخطأ فيها الطفل؛ يُحفَظ الاختيار مع القياس ويظهر في نتيجة التقييم، وفي صفحة للقراءة فقط لكلّ قياس سابق، وفي عمود الطلاقة بملفّ الطالب. توثيق للملاحظة فقط — لا تتغيّر الكلمات الصحيحة في الدقيقة ولا الدقّة ولا بطاقات المؤشرات ولا المنحنى ولا قرارات الدعم. عملية جديدة واحدة. يبلغ amal-api.yaml الآن 348 مسارًا / 379 عملية.

  • POST /api/orf/assessments/{id}/stop يقبل اختياريًّا error_details[] ({ word_index, group_index, part: "letter" | "mark", mark_index?, char }) إلى جانب error_word_indices. يجب أن يُشتقّ كلّ قيد من كلمة النصّ بمقسِّم مجموعات الحروف نفسه المستخدم في استيراد الأسئلة (graphemeSplitVersion v1)؛ أيّ اختلاف، أو كلمة خارج المجموعة النهائية، أو تفاصيل بلا مجموعة نهائية ← 422 ولا يُكتب شيء. تُحفَظ الصفوف في الجدول الجديد oral_reading_error_detail (إضافة فقط؛ الترحيل 20260909120000_orf_error_detail).
  • GET /api/orf/assessments/{id} يُرجع قياسًا واحدًا للقراءة فقط: كلمات النصّ، وerrorWordIndices (المجموعة المحتسبة؛ الصفوف القديمة تعود إلى نقرات السجلّ بلا تكرار)، وerrorDetails، وأرقامًا فارغة حتى الإنهاء. نطاق المعلّمة ← 403؛ مؤسسة أخرى ← 404.
  • إصلاح: صار GET /api/reports/students/{id}/sessions?kind=orf (وتفصيل orf) يعرض قياسات القراءة للطلاب الحقيقيين — كان يقرؤها بمعرّف الملفّ بينما يكتبها القياس بمعرّف المستخدم.
  • واجهة المعلّمة: زرّ «تفصيل» بجانب الكلمات المميَّزة (أثناء القراءة وفي خطوة آخر كلمة)؛ النافذة؛ بطاقة «الكلمات المقروءة خطأً» في النتيجة؛ الصفحة /teacher/students/{id}/orf/{assessmentId} من «قياسات القراءة الأخيرة»؛ كتلة «آخر قياس» في عمود الطلاقة بالملفّ.
  • تصحيح الاحتساب (مراجعة ما قبل الدمج): صار حاسب الطلاقة يحتسب على شبكة الكلمات الصفرية الأساس التي تستخدمها كلّ النصوص المزروعة — words_attempted = last_word_index + 1 والفهرس 0 (الكلمة الأولى) خطأ مشروع. سابقًا لم تكن الكلمة الأولى المقروءة خطأً تُحتسب، وكانت القراءة الكاملة تنقص كلمة. صار stop معاملة واحدة (صفّ الجلسة + صفوف الأجزاء + صفّا cbm_scores)؛ يخزّن result.scoredErrorWordIndices مجموعة المحرّك ضمن المدى؛ ويُسقَط تفصيلٌ على كلمة مميَّزة بعد آخر كلمة وصل إليها الطالب مع علامتها (لا 422 أبدًا)؛ ويقبل حمل orf_probe_event المفتاحين detailCount وadministered.

نوافذ التقييم: تقويم المشرف حسب المؤسسة/المدرسة وفتح المعلّمة للتقييم لصفّها، 2026-09-09

خادم + مشرف + معلّمة + طالب. يُعرض التقييم على الطفل — ويمكنه بدؤه — فقط داخل نافذة تقييم مفتوحة (بداية العام / منتصفه / نهايته). تأتي النافذة من فتحٍ قامت به معلّمة الصف، وإلّا فمن التقويم الذي ضبطه المشرف (المدرسة ← المؤسسة ← العامّ، لكل نافذة). لا شيء مفتوح = لا تقييم. لم يعد التطبيق يقرأ ملفّ تعريف amal_cycle (يقرؤه فقط مكدّس Playwright الوهمي خلف E2E_MOCK_SEAM=1). 6 عمليات جديدة. يبلغ amal-api.yaml الآن 347 مسارًا / 378 عملية.

  • GET /api/admin/screening-windows?organizationId&schoolId يُرجع النوافذ الثلاث الفعلية في نطاق ما (startsOn / endsOn تواريخ، source، inherited؛ تواريخ null = غير مُفعَّلة). PUT /api/admin/screening-windows/{window} ينشر مدى تواريخ في نطاق الجسم (نشر مع إصدار، 409 concurrent_publish؛ 422 إذا كانت البداية بعد النهاية، أو تداخل المدى مع نافذة شقيقة في النطاق نفسه، أو نطاق غير صالح). DELETE /api/admin/screening-windows/{window}?… يزيل التخصيص. مشرف المنصّة الفعلي، كمسارات المخطّط. يكتسب سجلّ تدقيق المخطّط windows (سجلّ التواريخ).
  • GET /api/classes/{classId}/screening-triggers و**POST …/screening-triggers** ({ window, startsOn, endsOn }، 31 يومًا كحدّ أقصى، فتحٌ واحد لكل نافذة ← 409 trigger_already_open) و**POST …/screening-triggers/{id}/close** — أيّ معلّمة نشطة في الصف تفتح أو تغلق تقييمًا لصفّها؛ المدير والمشرف يقرأان فقط. يحمل ردّ الفتح calendarWindow ليحذّر الواجهة عند مخالفة التقويم.
  • GET /api/student/today-plan يكتسب screening: { window, source } | null؛ ويكون nextAction هو "diagnostic" فقط عندما تكون نافذة مفتوحة لم يكملها الطفل هذه السنة الدراسية (1 آب ← 31 تموز)، أو عند وجود جلسة جارية.
  • POST /api/diagnostic-sessions/start: صار screeningCycle اختياريًّا. عند إغفاله يحدّد الخادم النافذة المفتوحة (فتح الصف أوّلًا ثم التقويم بحسب النطاق). لا يجوز للطالب تسمية نافذة غير مفتوحة له اليوم (409 window_mismatch)؛ ولا شيء مفتوح ← 409 no_open_window (لا تُنشأ جلسة). يجوز للمعلّمين والمشرفين تسمية النافذة صراحةً؛ وd_triggered صريح دائمًا. يسجّل صفّ الجلسة screeningSource (class_trigger | calendar | explicit).
  • صفحة المشرف: شريط «مواعيد التقييم» فوق شبكة المخطّط — ثلاث بطاقات بالتواريخ ورقائق الوراثة ومحرّر مدى التواريخ. صفحة صفّ المعلّمة: لوحة «التقييم المفتوح» مع «افتح تقييمًا» (النافذة + التواريخ، افتراضيًّا اليوم ← +6 أيام) و«إغلاق». الطالب: شاشة هادئة «لا يوجد تقييم مفتوح الآن» عندما لا شيء مفتوح.
  • الطرح: لا نافذة مفتوحة في أيّ مكان حتى يضبط المشرف التواريخ أو تفتح المعلّمة تقييمًا — اضبط التواريخ لمؤسّساتك فور النشر. يزرع مُجهِّز العرض التجريبي نافذة بداية عام مفتوحة في مؤسسة العرض. الترحيل 20260909100000_screening_windows.

تثبيت نطاق المؤسسة في قائمتي المدارس والصفوف؛ وقائمة المستخدمين عبر المؤسسات؛ وسجلّ التدقيق يسمّي الناشر؛ وتوحيد تسميات الأدوار، 2026-09-09

إصلاح واحد في عزل المستأجرين مع متابعات صفحات المشرف من مصفوفة الاختبار الشامل. لا عملية جديدة؛ يبقى amal-api.yaml عند 341 مسارًا / 370 عملية.

  • GET /api/schools?organizationId= وGET /api/classes?organizationId= لم يعودا يسمحان لمستدعٍ مقيّد بمؤسسة بقراءة مؤسسة أخرى: يُحترم المُعامل لمشرف المنصّة فقط (مع تسجيل التجاوز)، ويبقى المستدعي داخل مؤسسته ويُتجاهل المُعامل. قبل هذا الإصلاح كانت المؤسسة المُمرَّرة تطغى على تثبيت المستأجر، فيستطيع مسؤول مؤسسة سرد مدارس وصفوف مؤسسة أخرى بما فيها رموز دخول الصفوف. تمرّ كل معالجات القوائم الآن عبر سياسة واحدة tenantWhere(c, { organizationId }).

  • GET /api/users?organizationId= يحصر قائمة مشرف المنصّة العابرة للمؤسسات في مؤسسة واحدة (مع تسجيل التجاوز)؛ ويبقى المستدعي داخل المؤسسة محصورًا بمؤسسته ويُتجاهل المُعامل. تعرض /admin/users عمود المؤسسة ومرشّحها لمشرف المنصّة (بحسب هويّته لا بعدد المؤسسات)، ويُتجاهل ?org= غير الصالح بدل أن تفشل الصفحة.

  • GET /api/admin/diagnostic-blueprint/audit-log تحمل صفوفه publishedByName (اسم الناشر fullNameAr وقت القراءة، وnull فقط إذا زال صفّ المستخدم)؛ وتعرضه صفحة السجلّ إلى جانب معرّف publishedBy الثابت.

  • تسجيل الخروج وكل مسارات الدخول تمسح ملفّ تعريف amal_cycle (كلمة المرور، الطالب، الرابط السحري، Google، التقمّص، الخروج من العرض التجريبي)، فلا يمرّر جهاز الصفّ المشترك مُحدِّد نافذة التقييم من طفل إلى الطفل التالي. أي كاتب مستقبلي يجب أن يضبطه بـ path=/ (lib/cycle-cookie.ts).

  • تسمية عربية واحدة لكل دور في هيكل التطبيق وصفحة الأدوار وحوار الإنشاء والمرشّحات وعروض النشاط وبوّابة التوثيق العربية (كانت أربع نسخ متباينة؛ مدير المؤسسة يُقرأ «مدير المؤسسة» في كل مكان). ويستخدم هيكل التطبيق الآن الصيغ النكرة نفسها المستخدمة في صفحات المشرف (مثل «معلّم» بدل «المعلّم» في الإعدادات وشريط التقمّص)؛ وتحتاج لقطات الانحدار البصري لـ /admin/users و/admin/roles إلى تحديث (pnpm --filter web visual:update).

متابعات دورة اختبار التقييم: حقل reason عند البدء، وتنبيه QA_040، وعدّاد أسئلة التقييم للمشرف، وإحصاء المحتوى، 2026-09-08

خادم + شبكة المشرف + محتوى. متابعات دورة اختبار تفعيل/تعطيل مهارات المخطّط بتاريخ 2026-09-08. لا نقاط وصول جديدة؛ يبقى amal-api.yaml عند 341 مسارًا و370 عملية (حقلا استجابة إضافيان).

  • POST /api/diagnostic-sessions/start يكتسب حقل reason إلى جانب firstItemId: no_blueprint (لم تُحلّ أي خلية لصفّ الطالب ونافذته في أي نطاق)، أو no_eligible_item (توجد خلية لكن لا عنصر تقييم قابلًا للتقديم لمهاراتها)، أو null عندما يُقدَّم عنصر. تجربة الطفل لا تتغيّر (تُترك الجلسة عند البدء وتظهر شاشة «لا توجد أسئلة جاهزة» الهادئة)؛ الحقل للمشغّلين ولتشخيص العميل.
  • QA_040 — بدء تقييم بلا ما يُقدَّم. فحص جديد في السجلّ (من 39 إلى 40 فحصًا، الشدّة high): البدء الفارغ يكتب صفًّا في platform_alert_log يسمّي المؤسسة والطالب والجلسة والصفّ والنافذة ونطاق المدرسة ومصدر المخطّط وحجمه وreason، ويُنبّه الهندسة — صفّ واحد لكل (نطاق المدرسة × الصفّ × النافذة × السبب) في اليوم، فصفٌّ كامل يعيد الضغط على «ابدأ» على خلية واحدة غير مُهيّأة يساوي تنبيهًا واحدًا؛ ولا يُعرض على لوحة المعلّم أبدًا. يظهر في GET /api/qa/runtime-alerts?qaCheckId=QA_040 لمشرفي المؤسسة. pnpm test:qa:040.
  • GET /api/admin/diagnostic-blueprint يكتسب skillTaqyeemCount (لكل مهارة نشطة، عدد عناصر quick_check التشغيلية غير التدريبية — المخزون الذي تسحب منه الشاشة الأولى) و**skillTaqyeemCountAudio** (المخزون نفسه مقصورًا على العناصر ذات الصوت، قاعدة الصوت أولًا للصفّ الأول) و**taqyeemScreenSize** (حجم الشاشة لكل مهارة كما يقرّره الخادم، 3). تُعلّم نافذة المشرف المهارة التي دون حجم الشاشة بشارة «n من 3 أسئلة تقييم»، وتستخدم عدّاد الصوت لخلايا الصفّ الأول (كانت شارة «لا يوجد محتوى بعد» تعدّ أي عنصر تشغيلي، فلم تحذّر قطّ من مهارة لها عناصر تدريب فقط).
  • pnpm --filter server content:census يطبع لكل مهارة أعداد التقييم (quick_check) والتدريب (practice) والمتابعة (progress_monitoring_probe) مصنّفةً بحسب شاشة الأسئلة الثلاثة (--json للآلات). لقطة 2026-09-08 في docs/product/taqyeem-content-census-2026-09-08.md.
  • المحتوى. عناصر الصور الخمسة عشر من دفعات الشريك التجريبية (DWR-D01 وصور خيارات PA-13 ومشاهد SENT-A01) التي كانت تشير إلى ملفات بديلة فارغة صارت تحمل رسومًا حقيقية على المسارات نفسها؛ لا تغيير في البيانات.

بدء تقييم بلا سؤال قابل للعرض يُترك ولا يُكمَل؛ وإصلاحات في تجهيز الحسابات، 2026-09-07

خادم + صفحات المشرف، من مصفوفة الاختبار الشامل التي مرّرت مخطّط النطاقات عبر الواجهة الفعلية. لا عملية جديدة؛ يبقى amal-api.yaml عند 341 مسارًا و370 عملية.

  • POST /api/diagnostic-sessions/start يترك الآن الجلسة التي لا يحمل مخطّطها المحلول أي سؤال قابل للعرض (فجوة صوتية في الصف الأول، أو خلية تسمّي مهارات بلا محتوى مؤلَّف): يحمل الردّ noEligibleItem: true مع firstItemId: null وstate.status: "abandoned"؛ ويُكتب الصف بالقيمة الجديدة no_eligible_item في sessionEndReason (الترحيل 20260907070000_session_end_reason_no_eligible_item). ويُرجع POST /api/diagnostic-sessions/{id}/finish على جلسة متروكة 404، فلا يستطيع العميل تحويل بداية بلا أي دليل إلى فحص مكتمل. ولا يمنع الصف المتروك بدءًا لاحقًا للطالب نفسه في النافذة نفسها. ويعرض تطبيق الطالب حالة هادئة «لا توجد أسئلة جاهزة الآن» بدل الاحتفال.
  • POST /api/users من حوار المشرف: يمكن إنشاء طالب بلا بريد ولا كلمة مرور؛ فيُنشئ الخادم اسم المستخدم والرمز السرّي من 4 أرقام ويعرضهما الحوار مرّة واحدة. و«مسؤول النظام» مع مؤسسة يُنشأ مشرفًا على تلك المؤسسة (scope: ORG)؛ وترك المؤسسة فارغة هو الاختيار الصريح لمسؤول عامّ على المنصّة.
  • صفحات المشرف: تُعاد تهيئة حوارات الإنشاء (مستخدم، مدرسة، صفّ، مؤسسة) عند فتحها من جديد؛ وتعرض قائمة الصفوف رمز الدخول المكوّن من 6 أرقام لكل صفّ. ولقائمة المؤسسة عند اختيار «مسؤول النظام» خيار صريح «بلا مؤسسة — مسؤول عامّ»، ويردّ POST /api/users بـ 422 عندما لا يتّفق scope المسؤول مع ربط المؤسسة (SUPER مع مؤسسة، أو ORG / SCHOOL بلا مؤسسة).
  • PUT /api/admin/diagnostic-blueprint/{grade}/{cycle} يردّ الآن بـ 409 (reason: concurrent_publish) عندما يسبقه نشرٌ آخر للخلية نفسها: صفٌّ نشط واحد لكل نطاق × صفّ دراسي × نافذة تفرضه قاعدة البيانات (فهرس فريد جزئي diagnostic_blueprint_active_cell، الترحيل 20260907080000_diagnostic_blueprint_active_cell_unique).
  • POST /api/diagnostic-sessions/start/re-diagnostic يفتح الجلسة قبل أرشفة قوائم تمرين الطالب؛ وحين لا يوجد عنصر قابل للعرض تُترك الجلسة (no_eligible_item) ويحمل الردّ noEligibleItem: true مع archivedQueueCount: 0، وتبقى خطّة التمرين كما هي.

مخطّط التقييم الأوّلي حسب المؤسسة والمدرسة؛ وبوّابة مشرف النظام الفعلي على لوحة الإدارة، 2026-09-07

خادم + شبكة للمشرف. صار مخطّط مهارات التقييم الأوّلي — أي المهارات الفرعية التي تغطّيها الجلسة الأولى لكل صفّ × نافذة فحص — قابلًا للضبط على مستوى المنصّة كلّها، أو مؤسسة واحدة، أو مدرسة واحدة. عملية جديدة واحدة. صار amal-api.yaml يضمّ 341 مسارًا و370 عملية.

  • النطاق على كل مسارات المخطّط. يُرجع GET /api/admin/diagnostic-blueprint?organizationId&schoolId الشبكة الفعلية لذلك النطاق؛ وتحمل كل خلية source (global أو org أو school) وinherited. ويقبل PUT /api/admin/diagnostic-blueprint/{grade}/{cycle} حقلي organizationId وschoolId في المتن وينشر على ذلك النطاق (لكل نطاق سلسلة إصداراته الخاصة). ويقبل GET /api/admin/diagnostic-blueprint/audit-log المرشّحات نفسها، ويحمل كل صفّ organizationId وschoolId وscopeLevel. يتطلّب schoolId وجود organizationId، ويجب أن تكون المؤسسة موجودة وأن تتبعها المدرسة (وإلا 422).
  • جديد: DELETE /api/admin/diagnostic-blueprint/{grade}/{cycle}?organizationId&schoolId يزيل التخصيص على ذلك النطاق (يصير الصفّ النشط غير نشط بلا خَلَف؛ ويُحفَظ السجل) ويُرجع effective — الخلية كما يحلّها ذلك النطاق الآن من نطاقه الأعلى، أو null إن لم تُضبط في أي مستوى. ويُرجع 404 عندما لا يوجد شيء نشط على ذلك النطاق.
  • الحلّ عند POST /api/diagnostic-sessions/start: مدرسة تسجيل الطالب النشط ← مؤسسة الطالب ← العامّ. يفوز أول صفّ نشط ويستبدل الخلية كاملة (لا دمج). وما زالت القائمة المحلولة تُنسخ على صفّ الجلسة، فلا يغيّر تعديلٌ لاحق للمخطّط جلسةً بدأت فعلًا.
  • بوّابة مشرف النظام الفعلي. صارت مسارات المخطّط ومسارات إدارة ملفات المعايير الأربعة تحت /api/admin/benchmark-profiles تتطلّب مشرف نظام على مستوى المنصّة (حسابًا خارج أي مؤسسة). يحمل كل مشرف مؤسسة رمز الصلاحية SUPER_ADMIN، فلم يكن الرمز وحده فحصًا كافيًا قطّ؛ ويتلقّى مشرف المؤسسة الآن 403، وتعرض صفحات الويب بطاقة «لمشرفي النظام فقط».
  • المخطّط البياني. يكتسب diagnostic_blueprint حقلين اختياريين organizationId وschoolId وحقلًا مشتقًّا scopeKey؛ والتفرّد على (scopeKey, gradeLevel, screeningCycle, version). تُبقي الترحيلة 20260907001000_r14_diagnostic_blueprint_scope كل الصفوف الموجودة على النطاق العامّ. وصار مزوّد العرض التجريبي يزرع خلاياه الافتراضية على نطاق مؤسسة العرض، لا على النطاق العامّ أبدًا.
  • لم يتغيّر: حدّ التغطية الأدنى لكل مجال في المحرّك. يتحقّق النشر من معرّفات المهارات والنطاق فقط، فقد تظلّ خلية ضيّقة على مستوى مدرسة تحلّ الطالب إلى ملفّ البيانات غير المكتملة في ذلك المجال (مقام التغطية قرار شريك معلّق).

متابعات مجموعات الدعم: صلاحية الخطط، وربط المعلّمة بمدرستها، وتوصيات المجموعة، 2026-09-07

عملية جديدة واحدة. صار amal-api.yaml يضمّ 341 مسارًا و369 عملية.

  • GET /api/support-groups/{id}/recommendations يُرجع صفوف توصيات TAW_01 (بالشكل نفسه لـ /api/workflow/recommendations/{classId}؛ ويحمل classId معرّف المجموعة) لأعضاء المجموعة؛ ويُعلَّم الصف review_required عند وجود تنبيه تراجع حاد مفتوح في أيّ صف للعضو.
  • صلاحية الخطط. يقبل POST /api/workflow/activate (mode=individual) حقل groupId بدل classId (واحد منهما فقط): يجب أن تملك المستدعية المجموعة غير المؤرشفة، وأن يكون الطالب عضوًا نشطًا فيها، وتُربط الخطة بصفّ الطالب نفسه (عضو بلا صفّ ← 422). وتصل المعلّمة المسؤولة أيضًا إلى POST /api/students/{id}/activate-bundle وإلى مراجعة/إنهاء الخطة لأعضائها (القرار: تدير معلّمة الدعم أعضاءها كمعلّمة صف). ويبقى التفعيل الجماعي في معالج الصف ومسوّداته مرتبطًا بالصف.
  • الضابط الثاني صار على الخادم في كل مسارات التفعيل: أيّ تنبيه تراجع حاد مفتوح (لم يُراجَع بعد) للطالب، أيًّا كان الصف أو النافذة التي رُفع فيها، ← 409 من POST /api/workflow/activate (الفردي والجماعي لأعضائه المؤكَّدين) ومن POST /api/cluster/bulk-activate ومن POST /api/students/{id}/activate-bundle (FR-TDS-18) — للخطة الجديدة فقط؛ ولا يُحجب مسار توجيهي (توصية بلا حزمة) أبدًا. وتقرأ صفوف review_required للصف والمجموعة المجموعة نفسها. ويسجّل المسار الفردي deliveryMode المختار في سجل القرار. ولا يمسّ التفعيل عبر المجموعة مسوّدة معالج الصف المحفوظة للمعلّمة.
  • DELETE /api/schools/{id} يُرجع 409 عند وجود معلّمة مرتبطة بالمدرسة عبر TeacherProfile.schoolId (القيد صار RESTRICT).
  • GET /api/users/me (TEACHER) يحمل profile.schoolId (قد يكون فارغًا).
  • POST /api/users (TEACHER) يقبل schoolId (يجب أن تكون في المؤسسة؛ وتُشتق من الصف الأول في classIds عند إغفالها) ويخزّنها في TeacherProfile.schoolId؛ ويضبطها أيضًا حقل school_ref في ملف الكادر، وجرى تعبئتها للمعلّمات ذوات المدرسة الواحدة. ويعتمد عليها GET /api/support-groups/owners?schoolId= أولًا.
  • داخليًا: بديل مشترك واحد لنطاق الطالب (resolveStudentScope) يحلّ محلّ ستّ نسخ خاصة بالوحدات؛ ولم يعد مدخل الحاوية يطبع عنوان قاعدة البيانات.

مجموعات الدعم: مجموعة خاصة بمعلّمة من عدّة صفوف، 2026-09-06

خادم + صفحات للمعلّمة ولمدير المدرسة ولمشرف المؤسسة (يُنشئ المشرف المعلّمة من «المستخدمون» ثم مجموعتها من /admin/support-groups). 11 عمليات جديدة. صار amal-api.yaml يضمّ 340 مسارًا و368 عملية.

  • GET / POST /api/support-groups يسرد المجموعات التي يصل إليها المستدعي (?includeArchived=true، ويُتجاهَل للمعلّمات) ويُنشئ مجموعة؛ ويسرد GET /api/support-groups/owners?schoolId= المعلّمات المؤهَّلات لتولّي مجموعة في تلك المدرسة (مقيَّد بالمدرسة: مرتبطات بها أو غير مرتبطات بأيّ مدرسة بعد؛ أسماء وعدد الصفوف فقط، دون بريد). لا تُنشئ المعلّمة إلا مجموعة تملكها في مدرسة تدرّس فيها؛ ويسمّي مدير المدرسة / المدير / المشرف المعلّمة المسؤولة، ويجب أن تكون من تلك المدرسة (403 وإلا).
  • GET / PATCH /api/support-groups/{id} يُرجعان التفاصيل مع الأعضاء النشطين (معرّف المستخدم + معرّف ملف الطالب + الصف) وتغيير الاسم؛ أمّا archived فللإدارة فقط (403 للمعلّمة المسؤولة)، والمجموعة المؤرشفة خارج متناول معلّمتها كليًّا. ويضيف POST /api/support-groups/{id}/members أعضاء بـ studentUserIds: يجب أن يكون كل طالب في متناول المنفّذ عبر التسجيل في الصف (المعلّمة من صفوفها، ومدير المدرسة من مدرسته؛ لا عبر مجموعة أخرى تملكها)؛ على دفعات، و409 على مجموعة مؤرشفة. ويُزيل DELETE /api/support-groups/{id}/members/{studentUserId} العضو إزالة ناعمة.
  • GET /api/support-groups/{id}/summary و**/domain-trend** و**/alerts** تُرجع كائنات الصف نفسها (ClassSummaryDTO وDomainTrendDTO وClassAlertsResponse) محسوبة على الأعضاء، فتُعيد لوحة المجموعة استخدام لوحة الصف دون تغيير.
  • الوصول. تصل المعلّمة إلى الطالب عبر التسجيل في الصف أو العضوية النشطة في مجموعة غير مؤرشفة تملكها، وتحترم كل وحدات الطالب هذا المسار البديل (بما فيها مراجعة/إنهاء خطة الدعم وعرض التجميع). الوصول عبر المجموعة تربويٌّ فقط: تبقى كتابات حساب الطالب (PATCH /api/students/{id}، وإعادة إصدار رمز الدخول، وإعادة تعيين كلمة المرور) لمعلّمة الصف والإدارة. وصار صندوقا GET /api/monitoring/alerts و**GET /api/cbm/alerts** يشملان الصفوف ∪ أعضاء المجموعات المملوكة. لا يتغيّر التسجيل في الصفوف ولا لوحات معلّمات الصفوف.

استيراد بيانات المدارس من ملفات CSV: المدارس والصفوف والكادر والطلبة من أربعة ملفات، 2026-09-02

خادم + معالج للمشرف لمسار تهيئة أول عميل. 6 عمليات جديدة. صار amal-api.yaml يضمّ 332 مسارًا و357 عملية.

  • POST /api/roster-import/batches (رفع متعدّد الأجزاء: ملفات CSV باسم schools وclasses وstaff وstudents؛ الطلبة إلزامي) يقرأ الملفات ويتحقّق منها ويطابقها ثم يُعيد دفعة مرحليّة — إمّا status: invalid مع أخطاء عربية مرقّمة بالسطر (لا يُكتب شيء)، أو status: previewed مع إجراء create أو update أو conflict لكل سطر. ويسرد GET /api/roster-import/batches الدفعات؛ ويُرجع GET /api/roster-import/batches/{id} كل الأسطر؛ ويُنزّل GET /api/roster-import/batches/{id}/report.csv تقرير الأخطاء (UTF-8 مع BOM).
  • PATCH /api/roster-import/batches/{id}/rows/{rowId} يسجّل قرار التعارض (accept_csv أو keep_amal أو skip_row) — التعارض مطابقة بالاسم العربي المعياري فقط، ولا يُدمج تلقائيًا أبدًا.
  • POST /api/roster-import/batches/{id}/commit ينفّذ الدفعة في معاملة واحدة ويُعيد بيانات دخول تُعرض مرة واحدة (كلمات مرور مؤقتة للكادر، ورموز من 4 أرقام للطلبة). 409 stale_preview عندما تكون دفعة أخرى قد أنشأت المعرّفات نفسها أولًا؛ و410 بعد انقضاء 24 ساعة؛ و422 للحالات batch_invalid وunresolved_conflicts وschool_principal_conflict.
  • نموذج الهوية. صار User.email قابلًا للفراغ (لا بريد للطلبة؛ ويبقى إلزاميًا للبالغين)، ويحمل كل من User وSchool وClass معرّفًا externalRef على مستوى المؤسسة — معرّف المدرسة نفسها ومفتاح عدم التكرار عند إعادة الاستيراد. وتُركّب أربعة أعمدة للاسم العربي (firstNameAr … familyNameAr) قيمة fullNameAr. ويقبل POST /api/users طالبًا دون email.
  • بيانات الدخول. صارت رموز الطلبة ذات الأربعة أرقام تُشفَّر بكلفة AUTH_STUDENT_PIN_BCRYPT_COST (الافتراضي 8)؛ وتبقى كلمات مرور البالغين على AUTH_BCRYPT_COST.

استوديو الأسئلة P2: إدارة النصوص، والإسناد الجماعي للقوالب، وتسميات المشتّتات، 2026-07-15

خادم الشريحة الثانية من استوديو الأسئلة. 5 عمليات جديدة. صار amal-api.yaml يضمّ 326 مسارًا و351 عملية.

  • تأليف النصوص. ينشئ POST /api/passages مسودة نصّ؛ ويحسب الخادم wordCount وsentenceCount من متن النص ويترك مقاييس المقروئية فارغة (يحسبها خطّ الإنتاج غير المتصل لاحقًا). يُرجع GET /api/passages/{id} الحقول القابلة للتحرير، والمقاييس للقراءة فقط، وقائمة الأسئلة المرتبطة مع مقتطفات قصيرة من نصّ السؤال (يُرجع 404 لنصّ خارج نطاق قراءة المستدعي). وPATCH /api/passages/{id} هو نقطة تحرير محتوى النص: يتحقّق If-Match على updatedAt ويعيد 412 عند شرط قديم، ويكتب كل حفظ صفًّا في passage_revision للإلحاق فقط ضمن المعاملة نفسها. ويسرد GET /api/passages/{id}/revisions سجل التعديلات. لا يوجد حذف؛ يُتقاعَد النص عبر حالته status.
  • نتائج تعديل المتن. يعيد تعديل نصّ المتن حساب العددين، ويضع علامة قِدَم على مقاييس المقروئية (metricsStaleAt)، ويضع علامة قِدَم على معايرة كل سؤال مرتبط تشغيليّ أو مُعايَر.
  • إنشاء سؤال فهم فارغ. صار POST /api/items مع هيكل blank يقبل passageId اختياريًا، فيبدأ سؤال الفهم من مسودة فارغة على نصّ مختار. ويُتحقَّق من ربط النص بالسؤال ضمن نطاق قراءة المستدعي، فيظهر نصّ من مستأجر آخر كأنه غير معروف.
  • الإسناد الجماعي للقوالب. يُسند POST /api/items/bulk-template قالبًا واحدًا (أو يزيله بقيمة null) عبر 1..200 سؤال. ويُبلّغ كل سؤال عن نتيجة مستقلّة (updated أو unchanged أو incompatible أو not_found أو conflict)؛ ولا يُوقِف فشلٌ واحد البقيةَ.
  • تسميات المشتّتات. صار GET /api/item-types/{code}/distractor-compat يُرجع كل نوع مشتّت مسموح ككائن يحمل تسمية عربية وعائلة، بدل نصّ رمز مجرّد.

معالجة فجوة محتوى التحقّق: حقل reason، وتنبيه QA_039، ومسح الطلبات المتوقّفة، 2026-07-12

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

  • استجابة GET /api/confirmation/next-item تكتسب حقلًا اختياريًا reason يُضبط كلما كانت done: true: no_open_request (لا شيء مستحق)، أو complete (اكتملت المجموعة الحالية للتو)، أو no_eligible_item (يوجد تحقّق مستحق لكن لا يتوفر عنصر مناسب بعد). تجربة الطالب لا تتغير في الحالتين؛ الحقل مخصّص للاستهلاك التشغيلي وواجهات المعلّم. كما يتجاوز التقديم الآن طلب التحقّق المحجوب بنقص المحتوى إلى الطلب التالي القابل للتقديم، فلا يعطّل مخزونٌ ناقص واحد بقية قائمة الطالب.
  • فحص جديد في السجل QA_039 (خطورة عالية): عند مصادفة المخزون الفارغ يُكتب سطر في platform_alert_log يسمّي المؤسسة والطالب والمهارة والنافذة والطلب (مرة واحدة لكل طلب)، ويُخطَر فريق الهندسة. يظهر عبر GET /api/qa/runtime-alerts.
  • أمر صيانة جديد confirmation:sweep يحوّل طلبات التحقّق المفتوحة لأكثر من 45 يومًا إلى abandoned (قيدٌ دفتريّ فقط؛ لا يُشتق أي قرار مهارة من مجموعة تحقّق غير مكتملة أبدًا).

سلسلة قواعد القرار R13: فحص من 3 عناصر، وعائلات المهارات المرتبطة، ومجموعة التحقّق، ومراجعة الصلاحية، 2026-07-12

خادم + نقطتا وصول جديدتان موجَّهتان للطالب. يُطبّق محرّك قرار المهارة الآن إجابات الشريكة المُقفَلة على أسئلة تغطية قواعد القرار الخمسة. يقدّم التشخيص الآن 3 عناصر بالضبط لكل مهارة فرعية (نطاقات نظيفة 0/3..3/3؛ وعتبة الكفاية تنتقل من 5 إلى 3). تُقرأ مهارات الطالب الشقيقة ضمن العائلة لتفسير الضعف بوصفه معزولًا/غير منسجم/واسعًا، لكن فقط عند وجود مهارتين مقيستين على الأقل (وإلا يبقى قرار المهارة الواحدة)، وهي دائمًا استرشادية — لا تغيّر أبدًا نتيجة المهارة نفسها. يفتح ضعف مهارة البوّابة الكامل (0/3) مجموعة تحقّق بالمستوى نفسه من الصعوبة، بينما يُوجَّه الضعف المصحوب بإشارة سلوكية مؤثِّرة إلى مراجعة صلاحية قصيرة بدل تأكيد الضعف.

  • GET /api/confirmation/next-item يقدّم عنصر مجموعة التحقّق التالي لأقدم تحقّق مستحَق للطالب (بنطاق الصعوبة نفسه للفحص الأولي؛ ويعيد done: true حين لا يوجد مستحَق أو تكتمل المجموعة).
  • POST /api/confirmation/responses يُرسل استجابة تحقّق واحدة (تُصحَّح في الخادم). يحمل الردّ فقط الحقل needMore — دون أيّ درجة أو حالة (لا يرى الطفل أيّ نتيجة داخلية). وعند اكتمال المجموعة (2–3 عناصر) يسجّل المحرّك النتيجة، ويحسم المهارة، ويغلق التحقّق.
  • ترحيلات جديدة: related_skill_family وconfirmation_request وskill_validity_review. لم يتغيّر شكل أيّ مسار قائم؛ والمساران الجديدان موصوفان ذاتيًّا في مرجع الـ API (المُولَّد آليًّا من amal-api.yaml).

لوحات المدير الإشرافية للمدير والمشرف: قراءات التنفيذ والطلاقة ومصفوفة المراجعة، 2026-07-11

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

  • GET /api/schools/{schoolId}/implementation-summary و GET /api/orgs/{orgId}/implementation-summary تُعيدان تجميع تنفيذ خطط الدعم (المطابقة): أعداد الخطط النشطة موزّعةً في adequate وinsufficient وunknown، ونسبة implementationRate، وأعلى ثلاثة رموز عوائق، وتفصيلًا لكلّ صفّ (مسار المدرسة) أو لكلّ مدرسة (مسار المؤسسة). النسبة مقياس مطابقة على الخطط لا النسبة العامة الواحدة المحظورة لمحو الأمية، وتكون null عندما يكون المقام صفرًا كي لا تظهر مدرسة كلّ خططها مجهولة بنسبة صفر بالمئة. مسار المدرسة محكوم بـVIEW_SCHOOL؛ ومسار المؤسسة بـVIEW_ORG.
  • GET /api/schools/{schoolId}/fluency-summary تُعيد أرقام القراءة الجهرية للمدرسة ولكلّ صفّ للنافذة المُحلّلة: عدد الطلاب المُقيَّمين، ووسيط الكلمات الصحيحة في الدقيقة، ووسيط الدقّة، وعدد من هم دون المرجع. الطالب الذي يكون حدّ صفّه قيمةً حارسةً من الشريك (NOT_APPLICABLE أو OPTIONAL_BASELINE_NO_CUT) أو غير مُحلَّل يُستبعد من عدد من هم دون المرجع، وهو null عندما لا يُحلّ أيّ حدّ عبر المجموعة. يُبلّغ benchmarkNote عن قابلية حلّ الحدّ. محكوم بـVIEW_SCHOOL.
  • GET /api/principal/schools/{schoolId}/review-matrix تُصنّف كلّ صفّ في واحدٍ من خمسة أرباع مغلقة (insufficient_evidence وimplementation_gap وgood_impl_low_growth وgood_impl_good_growth وneeds_monitoring) مع إجراء مُقترح مرافق بواحدٍ لواحد. تسبق الأدلّة غير الكافية أولًا (الصفّ الذي لا زوج نوافذ قابلًا للمقارنة له لا يُحكَم عليه أبدًا)، ثمّ بوّابة المطابقة (نتائج خطة غير مُنفّذة لا تُقرأ دليلًا على الخطة)، ثمّ الفاعليّة. هذا عون لجدول أعمال الاجتماع لا حُكم. محكوم بـVIEW_SCHOOL.
  • إعادة تجميع اتجاهات المؤسسة إلى نوافذ التقييم. أصبح GET /api/orgs/{orgId}/trends يجمّع محوره السينيّ على evidenceWindow للّقطة (BOY/MOY/EOY) بدلًا من الشهر التقويميّ. تغيّرت مصفوفة OrgTrendsDTO.windows من string[] إلى { bucketId, window, yearLabel }[]، وتحمل كلّ نقطة اتجاه الحقول الثلاثة ذاتها؛ ويُرتَّب المحور زمنيًّا (السنة، ثمّ BOY فـMOY فـEOY). على المستهلكين الذين يقرؤون سلاسل النافذة القديمة "YYYY-MM" أن يتكيّفوا.
  • تقرير المجلس بصيغة PDF أصبح تقريرًا مدرسيًّا من سبعة أقسام. يعرض GET /api/schools/{schoolId}/board-pdf ملخّص المدرسة، والتقييمات الشاملة الثلاثة، وتوزيع المجالات، ودقّة القراءة وطلاقتها، ومقارنة الصفوف، ومتابعة تنفيذ خطط الدعم. يقرأ كلّ قسم وحدته الشقيقة بأمان ليّن: المصدر غير المتاح يتراجع إلى سطر «لم يُقيَّم بعد» هادئ واحد، لا إلى رقم مُلفَّق، وتبقى وضعيّة الإخفاق المغلق للملفّ كاملًا (خطأ العرض أو المهلة أو تجاوز الحجم يُعيد 503) دون تغيير.

يُنفّذ FR-FID (المطابقة وبوّابة تصعيد B.21) وقاعدة الأدلّة غير الكافية GSR-01 ومراجع FR-CBM النافذيّة وتجميع المجال الكبير (docs/product/prds-v2/30-intervention-and-monitoring/35-fidelity-tracker.md و 33-fluency-measurement.md وdocs/product/prds-v2/60-supporting-features/69-reporting-apis.md). يبقى قراران للشريك: الصياغة العربيّة لأرباع مصفوفة المراجعة الخمسة وإجراءاتها مسودّة، وعرف عرض النسبة المئويّة لمعدّل المطابقة بانتظار التأكيد.

عدد العمليات: +4 (اثنتان لملخّص التنفيذ، وواحدة للطلاقة، وواحدة لمصفوفة المراجعة). كان العدّاد المتسلسل في القيود السابقة قد تخلّف عن العمل المُتداخل؛ والمرجعيّ amal-api.yaml أصبح الآن 305 مسارات و328 عمليّة.

استوديو الأسئلة: محرّكات عرض الطالب + محرّرات مفتاح الإجابة البنيوية (QS-P2/P3)، 2026-07-09

واجهة تأليف للمسؤول إضافةً إلى نوعين جديدين من الأسئلة. أصبح استوديو الأسئلة على /admin/questions يُعاين الآن أنواعًا أكثر بكثير من الأسئلة تمامًا كما يراها الطالب، ويضيف محرّرات بنيوية لمفتاح الإجابة لأسئلة التركيب والكتابة والحركات، ويجمع منتقي المهارة حسب الصفّ. لا عمليّات واجهة برمجية جديدة: النوعان الجديدان صفّان في item_type_catalog يُقدَّمان عبر مسارات العناصر القائمة، وكلّ محرّر مفتاح يكتب عبر نقطة الاختناق القائمة PATCH /api/items/{id}. سطح الواجهة البرمجية المنشور دون تغيير.

  • 9 محرّكات عرض تُرقّى إلى إنتاج الطالب الحيّ. chip_fill (ملء فراغ داخل السياق)، order_builder ← order_all (إعادة ترتيب)، tap_boundary ← syllable_cut، tap_tokens ← token_flow، letter_hunt ← scatter، diacritic_pick ← harakat_word، anagram ← tile_blend، إضافةً إلى نوعَي التفاعل الجديدين كليًّا أدناه. كلّ منها إسقاط مُقدَّم حقيقي، لا معاينة صوريّة: تعرض معاينة المسؤول المطابقة للواقع مخرجات servedItem() نفسها التي يتلقّاها الطالب.
  • نوعان جديدان من الأسئلة + أنواع تفاعل عند التقديم. TYPED_SPELLING (لوحة مفاتيح عربية على الشاشة، يُصحَّح باستراتيجية typed_exact الجديدة) وMULTI_SLOT_CLOZE (ملء فراغات متعدّدة عبر نصّ متّصل، يُصحَّح باستراتيجية slot_vector الجديدة). كلاهما من الطرف إلى الطرف: نوع العنصر + استراتيجية التصحيح
    • إسقاط التقديم + نوع الإجابة + المُصحِّح + العارض + استعادة الذاكرة المؤقتة. تنضمّ أنواع التفاعل الجديدة إلى المجموعة القائمة خلف إسقاط تقديم مُقيَّد بقائمة سماح ولا يُسرِّب المفتاح.
  • 7 منافذ نموذج أوليّ للمعاينة فقط. open_text وmatch_pairs وgroup_sort وstepwise وpassage_set وtap_region وtrace تُعرَض داخل معاينة المسؤول مع شارة بيانات عرض تجريبية. هي للمعاينة والتأليف فقط (لا تقديم للطالب ولا مُصحِّح) بانتظار قرارات إنتاج لاحقة.
  • 5 محرّرات بنيوية لمفتاح الإجابة تحلّ محلّ ملخّص «مفتاح الإجابة» للقراءة فقط في محرّر السؤال: محرّرا رفّ وتسلسل لـ tile_blend/word_order، ومحرّر مقصّ لمواضع القطع لـ syllable_cut (يُصلح أيضًا خطأ حقلٍ خاطئ كان يترك صفّ القطع فارغًا)، ومحرّر لوحة مفاتيح وكلمة هدف لـ typed_spelling، ومحرّر حروف أساس وحرف هدف لـ harakat_word. ويؤلّف محرّر تجريبي من الطبقة B أشكال منافذ المعاينة الأربعة (أزواج / مجموعات / خطوات / مناطق) ليعرض النموذج الأوليّ بيانات حقيقية بدل العيّنة. كلّ محرّر يكتب interactionConfig / interactionKey عبر نقطة الاختناق PATCH نفسها، مع بقاء سجلّ التعديلات للإلحاق فقط والتحقّق المطابق للبوّابة وتقسيم قائمة منع الإعداد/المفتاح (V-12) دون تغيير.
  • منتقي مهارة واعٍ بالصفّ. أصبحت قائمة «المهارة» في محرّر السؤال مجمّعة حسب صفّ العنصر (تتصدّرها المهارات المستخدَمة أصلًا في ذلك الصفّ) ولا تُخفي أيّ مهارة إخفاءً قسريًّا.

التصميم: docs/design/qs-p2-engine-ports.md + docs/design/qs-p3-key-editors.md. تضيف الهجرات نوعَي العنصر TYPED_SPELLING / MULTI_SLOT_CLOZE واستراتيجيتَي التصحيح typed_exact / slot_vector.

إدارة المستأجرين التجريبيين لمشرف النظام (WP-DEMO-ADMIN-MGMT)، 2026-06-28

الخادم وواجهة الإدارة. سطح مشرف النظام للإشراف على كل مستأجر تجريبي ذاتي التسجيل. 4 عمليات جديدة.

  • مسارات demo-admin جديدة، جميعها لمشرف النظام الحقيقي فقط (skipTenantFilter): يعرض GET /api/admin/demo-tenants المُسجِّل والحالة وتاريخ الانتهاء وآخر استخدام وأعداد الصفوف والطلاب؛ ويقوم POST …/{id}/revoke بحذف المؤسسة حذفًا ناعمًا وتعليق مستخدميها وإنهاء الجلسات ووسم التسجيل ملغى؛ ويمدّد POST …/{id}/extend مدّة الثلاثين يومًا أو يعيد تفعيل مستأجر انقضت مدّته؛ ويعيد POST …/{id}/reissue إصدار بيانات الدخول المؤقتة ويعرض حمولة الترحيب مرّة واحدة (لا قراءة لنصّ صريح مخزّن ولا بريد لإعادة الإرسال).
  • صلاحية requirePermission("SUPER_ADMIN") ضرورية لكنها غير كافية، لأن كل شخصية ADMIN تحملها. يردّ فحص داخل المعالِج بـ 403 لأي مشرف داخل مؤسسة، ويثبت ذلك اختبار عزل مستأجرين مُسمّى.
  • كل إجراء يخصّ دورة حياة بيانات الدخول وإدارة النسخة التجريبية مُدوَّن بنمط الإلحاق فقط: demo_revoke وdemo_extend وtemp_credential_issued.
  • يؤدّي تسجيل دخول ناجح إلى مؤسسة تجريبية (بكلمة المرور أو بالرمز السريع) إلى تحديث lastAccessedAt للتسجيل، فيبقى مؤشّر آخر استخدام في قائمة الإدارة حيًّا.
  • واجهة الإدارة: صفحة لمشرف النظام على /admin/demo-tenants فيها لكل صفّ إلغاء وتمديد وعرض بيانات الدخول.

يُنفّذ القسمين 5.7 و5.8 من docs/superpowers/specs/2026-06-27-in-house-demo-signup-design.md (يحلّ OI-2: السطح تحت admin/). يرتفع إجمالي سطح الواجهة إلى 278 مسارًا.

شخصية النسخة التجريبية وحارس الصندوق والتقمّص (WP-DEMO-ROLE)، 2026-06-28

الخادم. يجعل المستأجر التجريبي المُجهَّز قابلًا للاستكشاف بالكامل وقابلًا للكتابة بأمان. عملية جديدة واحدة.

  • شخصية DEMO_ADMIN جديدة (الشخصية السابعة في PersonaKey) بمجموعة صلاحيات منتقاة 13 من 25. تحمل كل أكواد القراءة إضافة إلى أكواد الكتابة التربوية داخل المستأجر، ولا تحمل أيًّا من أكواد الإرسال الخارجي أو التزويد أو الإعداد العام أو العابر للمستأجرين. يبقى ثابت الإغلاق على 25 كودًا محفوظًا.
  • يُستبدل حارس الكتابة الشامل requireNotDemo بـ requireDemoOutboundBlock. يحجب فقط المسارات الخارجية (LMS) والمسارات الهدّامة بنيويًا (حذف المؤسسة والمدرسة وإنشاء المؤسسة) والكتابات العامة أو العابرة للمستأجرين (استيراد بنك العناصر واعتماده وترقيته وتقاعده، إضافة إلى كتابات ملفات المعايير ومخطط التشخيص). ويرفع الحجب عن كل كتابة تربوية أو تسجيلية داخل المستأجر، بما في ذلك حذف الصف، فهو قابل للاسترجاع ويبقى داخل الصندوق المؤقت. القراءات لا تُحجب أبدًا.
  • POST /api/demo/impersonate هو تقمّص مُقيَّد. يصكّ DEMO_ADMIN رمزًا حقيقيًا لكل شخصية لأحد المستخدمين المبذورين من الشخصية المطلوبة، محصورًا في مؤسسة العميل التجريبية نفسها (أي هدف خارج المؤسسة غير قابل للوصول ويُعيد 404). يحمل الرمز المصكوك صلاحيات الشخصية الهدف الحقيقية. كل إصدار مُدقَّق بالإلحاق فقط (صفّ DemoImpersonationLog إضافة إلى صفّ demo_impersonation_start في AuthEventLog)، ويُعيد GET /api/auth/me الآن impersonatedBy لشريط «الاستكشاف بصفة شخصية».

يُنفِّذ المواصفة §5.6 من docs/superpowers/specs/2026-06-27-in-house-demo-signup-design.md (يحسم OI-1 وOI-4). عدد العمليات: +1. أصبح amal-api.yaml الآن 274 مسارًا / 293 عملية.

تسجيل ذاتي للنسخة التجريبية (WP-DEMO-PROVISION-BE)، 2026-06-28

الخادم. تسجيل ذاتي عام للنسخة التجريبية مع تجهيز مستأجر مستقل لكل عميل محتمل. عمليتان جديدتان.

  • POST /api/demo/register تسجيل محمي بالكابتشا ومحدود المعدّل. يُنشئ صفّ DemoRegistration قيد الانتظار ويُدرج تجهيز مستأجر تجريبي معزول وكامل البيانات في الخلفية، ثم يُعيد { registrationId }.
  • GET /api/demo/register/{id}/status يستعلم عن حالة التجهيز. يُعيد حمولة الترحيب لمرة واحدة (رابط الدخول مع بيانات الاعتماد التجريبية لكل شخصية، بما في ذلك quickCode وclassId للطالب التجريبي) فقط عندما تكون الحالة ready ولم تُستهلك الحمولة بعد.

يُعيد التجهيز استخدام خط بذر النسخة التجريبية (نُقلت مكتبة البذر إلى src/modules/demo/seed/) على مؤسسة جديدة مع عزل نطاق البريد لكل مستأجر، ثم يصكّ بيانات اعتماد مؤقتة إلزامية التغيير. وهو غير حسّاس للتكرار وآمن لإعادة المحاولة. يتولّى أمر demo:sweep انتهاء الصلاحية بعد 30 يومًا. يُنفِّذ المواصفة §5.3/§5.4/§5.5/§5.8 من docs/superpowers/specs/2026-06-27-in-house-demo-signup-design.md.

عدد العمليات: +2. أصبح amal-api.yaml الآن 273 مسارًا / 292 عملية.

طبقة التحقق من الكابتشا (WP-CAPTCHA)، 2026-06-28

بنية تحتية. أُضيفت طبقة التحقق من الكابتشا على جانب الخادم باستخدام Cloudflare Turnstile. لا عمليات API جديدة. متغير البيئة TURNSTILE_SECRET اختياري في بيئة التطوير (المُدقِّق الوهمي يقبل جميع الرموز) ومطلوب في الإنتاج (يفشل الخادم عند الإطلاق بصوت عالٍ إذا لم يُضبَط، لمنع اختفاء البوابة بصمت). نقطة الاستدعاء الإلزامية قبل الكتابة ستصل مع WP-DEMO-PROVISION-BE.

يُنفِّذ المواصفة §5.2 / القرار D7 من docs/superpowers/specs/2026-06-27-in-house-demo-signup-design.md.

عدد العمليات بدون تغيير: 285 عملية في amal-api.yaml (لم تُضَف أي مسارات).

إعدادات إمكانية الوصول لكل طالب (WP-PSA-BE)، 2026-06-27

الخادم. يصبح مسار إمكانية الوصول الخاص بكل طالب فعّالًا وآمنًا من ناحية القياس. عمليّتان جديدتان (مسار جديد واحد فيه PATCH وGET) ترفعان الإجمالي المنشور إلى 285 عمليّة في amal-api.yaml.

  • PATCH /api/students/me/accessibility-config مسار جديد. يضبط الطالب بنفسه حقوله الخمسة الخاصة بالعرض فقط (dyslexiaFont وhighContrast وlargerText وaudioFirst وreducedMotion). لا يحمل المسار /me أي معرّف للطالب، فلا شيء يمكن العبث به (آمن من ثغرة IDOR)؛ ويُحَل ملف الطالب من الجلسة على الخادم. يكتب دور STUDENT وحده، ويُفرَض ذلك بفحص داخل المعالِج لأن صلاحية VIEW_OWN_PROFILE يملكها كل دور، فبوّابة الصلاحية وحدها ليست هي القيد.
  • GET /api/students/me/accessibility-config مصدر التحميل المبدئي للطالب: الإعدادات الحالية مع رقم نسختها.
  • PATCH /api/students/{id}/accessibility-config، مسار المعلّم والوليّ الحالي، صار يدعم الدمج على مستوى الحقل والتزامن المتفائل والتدقيق.

معلومات مهمة لمستهلكي الواجهة البرمجية:

  • استجابة ثلاثية الحالة. كل حقل من الحقول الخمسة هو true أو false أو null. القيمة null تعني “غير مضبوط”، فيحلّها العميل إلى الإعداد الافتراضي لنظام التشغيل؛ أما false فهو “إيقاف” صريح. لا تعامل الحقل الغائب على أنه false.
  • التزامن المتفائل. أرسِل قيمة accessibilityConfigVersion التي قرأتها أخيرًا في ترويسة If-Match. تُعيد أي كتابة متزامنة سبق أن رفعت النسخة الرمز 409، فأعِد الطلب GET ثم حاول مجددًا. احذف If-Match لتطبيق مبدأ آخر كتابة تفوز (آمن لإعادة الإرسال دون اتصال).
  • الدمج على مستوى الحقل. يغيّر جسم الطلب PATCH المفاتيح التي يحملها فقط، وتُحفَظ بقية المفاتيح دون استبدال الكائن كاملًا. الكتابة بقيمة مطابقة لا تُحدِث أثرًا (لا رفع للنسخة ولا صفّ تدقيق).
  • التدقيق. تُلحِق كل كتابة فعليّة صفًّا في student_accessibility_config_log يسجّل من ومتى وأي حقول والنسخة الناتجة. الجدول للإلحاق فقط.
  • للعرض فقط. لا تقرأ أي وحدة قياس أو قرار الحقل accessibilityConfig، فلا يمكن لحقل يضبطه الطالب أن يؤثّر في اختيار البنود أو تقديرات القدرة.

تظهر المسارات الجديدة في مرجع الواجهة البرمجية بعد openapi:generate.

واجهة برمجة التجربة التشخيصية التفاعلية (WP-11-BE) — 2026-06-25

الخادم. ثلاثة مسارات جديدة مجهولة (لا تتطلّب تسجيل دخول أو حساب) ضمن /api/teaser/* تُفعِّل ميزة “جرِّب التشخيص” الترويجية. 3 عمليّات جديدة ترفع الإجمالي المنشور إلى 262 عمليّة وقت هذا القيد. أضافت حزم العمل اللاحقة مسارات إضافية؛ الإجمالي الحالي 283 عمليّة (مُتحقَّق منه في amal-api.yaml).

  • POST /api/teaser/sessions يبدأ تجربة تشخيصية للصف المحدّد (1-4). محدَّد بـ 3 جلسات لكل عنوان IP في الساعة. يُعيد رمز الجلسة و10 بنود مُنقّاة مع حذف مفاتيح الإجابة. يُعيد 503 إن لم يكن ثمة مجموعة بنود فعّالة للصف المطلوب.
  • POST /api/teaser/sessions/{id}/finish يُصحِّح الإجابات المُرسَلة باستخدام مُقدِّر راش الحقيقي ويُعيد نطاق تمركّز لمهارة فرعية واحدة (meets / approaching / below / severe) مع تسميات ميزان العربية ونصّ إخلاء مسؤولية باللغة العربية.
  • POST /api/teaser/leads يُسجِّل بريد إلكتروني أو رقم واتساب اختياريًّا. صفّ واحد لكل جلسة (upsert) فلا يُغرَق الجدول بطلبات متكرّرة.

معلومات مهمة لمستهلكي الواجهة البرمجية:

  • تحمل الأوراق الثلاثة security: [] في مواصفة OpenAPI. لا يُطلَب أي ترويسة Authorization.
  • يجب إرسال رمز الجلسة الصادر عند البدء إلى مساري finish وleads. رمز خاطئ يُعيد 401؛ إعادة الإرسال إلى finish يُعيد 409.
  • يُحسَب النطاق بناءً على عتبات لوجيتية ثابتة محايدة (لا تعتمد على ملفات المعايير لكل دولة) لأن الزائر المجهول لا دولة له. التجربة مصرَّح عنها صراحةً بوصفها عيّنة.
  • لا كتابة في أي جدول قياس أو إتقان أو أدلة طوال مسار التجربة. التجربة معزولة تحليليًّا عن خطّ الإنتاج التشخيصي.
  • يُخزَّن عنوان IP فقط كقيمة هاش مُملَّحة لأغراض تحديد معدل الطلبات والتحليل. لا يُحفَظ العنوان الخام أبدًا.
  • تحمل الجداول الثلاثة الجديدة (teaser_session وteaser_lead وteaser_item_set) القيمة organizationId = null (الاصطلاح العالمي نفسه المستخدَم في بنك الأسئلة).

تظهر المسارات الجديدة في مرجع الواجهة البرمجية بعد تشغيل openapi:generate.

بنود مفتوحة: يُعيد الصفّان 1 و3 حاليًّا 503 لغياب مهارة فرعية تحوي 10 بنود مؤهَّلة في الذخيرة الحالية. يجب أن تتعامل الواجهة الأمامية (WP-11-FE) مع هذا الخطأ بشكل سلس.

المواصفة: docs/superpowers/specs/2026-06-25-wp11-teaser-design.md (FR-6.3). الهجرات: wp11_teaser + wp11_teaser_lead_unique.

جولة المستأجر التجريبي (WP-12-FE) — 2026-06-25

عملية واحدة جديدة — GET /api/demo/access (عامة، لا تتطلب مصادقة) — تُشحن مع الواجهة الأمامية. تُسلِّم هذه الحزمة مدخل العرض التجريبي العام بنقرة واحدة، فوق المستأجر التجريبي الذي بنته WP-12-BE.

ما الذي تغيّر:

  • صفحة /demo لاختيار الشخصية. مكوّن خادمي يقرأ GET /api/demo/access وقت الطلب (يقرأ الخادم مؤسسة isDemo=true فقط) ويعرض بطاقة لكل شخصية بالغة، إضافةً إلى بطاقة الطالب مع منتقي رمز سريع لكل صف. “ادخل كـ…” يُدخل الزائر مباشرةً إلى المستأجر التجريبي — دون تسجيل.
  • علامة الكوكي amal_demo. تضبط إجراءات الدخول التجريبي amal_demo=1 مع كوكيز الجلسة. شريط DemoBanner مُركَّب في كلا القالبين (قالب البالغين + عالم الطالب) يقرؤها ويعرض شريطًا دائمًا “أنت في الوضع التجريبي” مع زرّي “تبديل الشخصية” (العودة إلى /demo) و”خروج” (مسح الجلسة). لا يراه المستخدمون الحقيقيون (يُعيد الشريط null دون العلامة).
  • لوحة بيانات الدخول. لوحة قابلة للطيّ تُدرج كلمة المرور المشتركة للبالغين، والبريد لكل شخصية، ورموز الطلاب السريعة لكل صف مع نسخ بنقرة — ليتمكّن المقدّم من نسخها على جهاز ثانٍ.
  • زرّ البطل + حالتا عدم التوفّر والخطأ. يكتسب بطل التسويق زرّ “جرّب العرض التجريبي”. عند عدم تهيئة مستأجر تجريبي تعرض الصفحة لوحة “غير متاح” هادئة مع زرّ الحجز؛ ويُعيد الدخول الفاشل التوجيه إلى /demo?error=1 بإشعار قابل للإغلاق.

يظهر المسار الجديد في مرجع الواجهة البرمجية بعد تشغيل openapi:generate. دليل التشغيل: wp-12-fe.md. اختبار E2E: apps/web/e2e/demo-flow.spec.ts. إمكانية الوصول: accessibility.spec.ts (“demo page: WCAG 2.1 AA”).

بنية المستأجر التجريبي (WP-12-BE) — 2026-06-25

الخادم فقط — لا مسارات API جديدة (حارس العرض التوضيحي هو وسيط، ليس مسارًا). تُسلِّم هذه الحزمة مستأجرًا تجريبيًا مكتفيًا بذاته يستطيع أي شخص مرور عبر جميع الشخصيات الست دون أن يتمكن من إتلافه بصفة دائمة. مرجع API دون تغيير.

ما الذي تغيّر:

  • علامة Organization.isDemo. عمود منطقي يُميّز المستأجر التجريبي. يضعه البذّار على true للمؤسسة التجريبية؛ تبقى كل المؤسسات الأخرى على false افتراضيًا.
  • حارس DEMO_READ_ONLY. وسيط requireNotDemo الجديد مُركَّب على ما يقارب 29 مجموعة من المسارات التدميرية وإدارة الموارد (إنشاء/تعديل/حذف المستخدمين، إنشاء/تعديل/حذف بنية المستأجر، ربط LMS وإجراء التزامن، إعادة توليد الرمز السريع، إرسال بريد إعادة كلمة المرور، إرسال إشعارات الوالدين). يُعيد 403 DEMO_READ_ONLY لأي مؤسسة isDemo=true. حلقة التفاعل الكاملة — التشخيص والتدريب والتسخين الذهني وقرارات المعلم وأدلة المراقبة وعلامات السياق وجميع عمليات القراءة — غير محجوبة. يمكن للزوار قيادة الحلقة بالكامل.
  • بذّار تجريبي متسامٍ. يُنشئ pnpm --filter server seed:demo مؤسسة تجريبية واحدة (الأردن) بمدرسة واحدة وثلاث فصول و60 طالبًا موزّعين على الصفوف 1–4، إضافةً إلى جميع الشخصيات البالغة الست ببيانات اعتماد محددة مسبقًا (*@amal-demo.jo / AmalDemo!2026). معلّم بطل مُعيَّن في فصلين لعرض منتقي الفصول المتعددة.
  • حالة حلقة حقيقية. يُشغّل البذّار خط أنابيب RTI الفعلي لمجموعة فرعية تمثيلية من الطلاب — إنهاء التشخيص ← محرك حالة المهارة ← اللقطات الكلية ← ترجمة الملف التعليمي ← توصيات الحزم. تعرض لوحات المعلومات بيانات حقيقية في الحركة، لا أرقامًا مصنّعة.
  • التسامي وإعادة الضبط. يمسح إعادة التشغيل حالة التشغيل المتراكمة (الجلسات، اللقطات، الملفات التعليمية، الحزم، صفوف المراقبة، علامات السياق، الإشعارات) ويُعيد اشتقاق الأساس. تُعدَّل صفوف الأشخاص على المفاتيح الطبيعية فتظل بيانات الاعتماد مستقرة عبر عمليات إعادة الضبط.
  • DEMO-GUIDE.md مُرسَل إلى docs/demo/ عند كل تشغيل للبذّار: جدول بيانات الاعتماد، جولة صفحات لكل شخصية، رمز الانضمام للفصل المتزامن.

مؤجَّل: ربط المجدول الليلي (موثَّق في دليل التشغيل، غير مُوصَّل)؛ صفحة /demo العامة وخطاف إعادة البذر داخل التطبيق (WP-12-FE، مرحلة لاحقة).

المواصفة: 2026-06-25-wp-12-be-demo-tenant-design.md. خطة البناء: §WP-12-BE FR-5.1/5.2. خطة الاختبار: wp-12-be.test-plan.md. دليل التشغيل: wp-12-be.md. الهجرة: Organization.isDemo. لا مسارات جديدة.

مُسجِّل المتصفّح وإرسال السجلّات بالدُفعات إلى الخادم (WP-LOG-FE) — 2026-06-25

الواجهة الأمامية. أصبح لتطبيق الويب الآن مُسجِّل متصفّح موحّد يطابق عقد مُسجِّل الخادم، إضافةً إلى عامل دُفعات يُرسل سجلّات التحذير والخطأ من العميل إلى نقطة النهاية القائمة POST /api/logs/client. لا توجد مسارات API جديدة (شُحنت نقطة النهاية مع WP-LOG-BE)، لذا مرجع API دون تغيير.

ما الذي تغيّر:

  • غلاف getLogger(module) بالمستويات الأربعة نفسها (debug وinfo وwarn وerror) وبالبنية الموحّدة نفسها لمُسجِّل الخادم. في وضع التطوير تُطبع كل المستويات إلى الـ console فقط. في بناءات الإنتاج يبقى DEBUG وINFO على الـ console فقط بينما يُرسَل WARN وERROR أيضًا إلى الخادم (FR-LOG-6).
  • عامل الدُفعات. تتجمّع صفوف WARN وERROR وتُرسَل عند بلوغ الذاكرة المؤقتة 50 صفًّا أو بعد 5 ثوانٍ، أيّهما أسبق. ردّ تجاوز الحدّ 429 يتراجع ثلاث مرات (500 و1000 و2000 مللي ثانية) ثم يُسقط الدُفعة مع أثر محلّي واحد. يحفظ فشلُ الشبكة الصفوفَ لإعادة محاولة لاحقة. كما تُرسَل الصفوف المؤقتة عند إخفاء التبويب أو إغلاقه.
  • التنقيح في جانب العميل. القائمة المغلقة لمفاتيح الأسرار والبيانات الشخصية في الخادم مُطابَقة في العميل وتُطبَّق على تفاصيل السجلّ قبل وصول أي شيء إلى الـ console أو الشبكة، فلا يغادر أيُّ سرٍّ المتصفّح. يُقنَّع البريد ويُحجَب الهاتف وسائر الأسرار.
  • lint:no-console لـ apps/web. يُرفَض استخدام console.* المباشر خارج مَصرف المُسجِّل. استخدِم getLogger بدلًا منه.

المواصفة: 81-logging-and-observability.md (FR-LOG-6). خطة الاختبار: wp-log-fe.test-plan.md. لا توجد هجرة قاعدة بيانات.

محرّك نمط المؤشرات الثمانية الزمني (R12 Q4) — 2026-06-23

الخادم + المواصفة. أصبحت المؤشرات الثمانية لمهارات القراءة العربية تعمل الآن عبر محرّك ثنائي المرحلة بآلية حالة تتبُّع ديناميكية لكل (طالب × نمط خطأ).

ما الذي تغيّر:

  • نموذج ثنائي المرحلة. مرحلة التقييم بدون تغيير — تنتقل الضعف المُثبَت مباشرةً إلى الملف التعليمي والحزمة دون تنبيه لعدد الأخطاء. مرحلة التدريب (جديدة) تُشغّل سلّم حالات لكل (طالب × micro_pattern_id): المستوى 1 (حدوث صالح واحد → candidate، صامت)؛ المستوى 2 (حدوثان+ مرتبطان في جلسة واحدة + بندان مستقلّان → automatic_support_active، بلا تنبيه للمعلّم)؛ المستوى 3 (3 حدوثات+ عبر جلستين+ بعد دعم تلقائي مُسلَّم والنمط يستمر → تنبيه معلوماتي خفيف للمعلّم؛ لا ينتظر أربع جلسات).
  • قاعدة ترابط الأخطاء (5 شروط جميعها مطلوبة). يُعدّ خطآن نفس النمط فقط إذا: المهارة ذاتها أو مهارة مرتبطة رسميًا (خريطة Q7) + نفس micro_pattern_id أو error_family + بندان مستقلّان صالحان للتحليل + صُمِّم البندان لكشف هذا النمط + يكشف الخيار المُختار نوع الخطأ. الانتماء لنفس المجال وحده غير كافٍ.
  • ضمان V-12 — المستوى 3 معلوماتي فقط. لا يُغيّر تنبيه المستوى 3 الدرجةَ / skill_status / domain_status / الملف / مستوى RTI / درجة التدخّل (scoreImpact = "none"). يكتب فقط في sub_flag_indicator_state + sub_flag_indicator_occurrence + platform_alert_log. مُطبَّق بـ lint:subflag-alert-no-mutation.
  • AR_LETTER_CONFUSION_FLAG مُعاد تسميته → AR_ORTHOGRAPHIC_CONFUSION_FLAG. يوضّح أن هذا المؤشر يغطّي التشابه البصري/الإملائي للحروف فقط (DWR-D04/D05)، لا التشابه الصوتي (PA-07). AR_SHADDA_FLAG معطَّل في هذه المرحلة (enabled=false).
  • جداول كتالوج عالمية جديدة: error_category (13 صفًّا)، error_micro_pattern (8 صفوف)، distractor_error_map (6 صفوف)، evidence_error_rule (EV01..EV06).
  • جداول تشغيل جديدة (بمستوى المؤسسة): sub_flag_indicator_state (سلّم قابل للتحديث عبر مسار كتابة وحيد) + sub_flag_indicator_occurrence (سجل إضافة-فقط لكل حدوث).
  • 5 حقول اختيارية جديدة في item_bank: microPatternId / errorFamilyId / confusionFamilyId / distractorErrorCode / designedToDetectPatternId (تُملأ فقط في بنود الكشف عن الأنماط).

بنود معلّقة (شريك): عتبة الإجابة السريعة في evidence_validity (EV06 — 300 ms مبدئية حتى يُحدَّد رقم RBM-08)؛ أثر الدعم التلقائي الملموس في المستوى 2؛ صفوف الأنماط المخصّصة لـ AR_SHORT_VOWEL_FLAG / VOCAB_ALERT / WR_SP_ALERT (تعمل حاليًا عند مستوى الفئة).

المواصفة: 23-student-profiles.md §4b + FR-SPR-4. الهجرة: r12_q4_subflag_engine. المصدر: إجابات الشريك Q4 (السطور 728-943) + File-2 v2 §14/15/17/23.

إعادة هيكلة حزم التدخّل — 14 حزمة + 7 كائنات مساندة (R12 Tier-D / Q11) — 2026-06-22

تغيير كاسر. يُعيد ملفّ الشريك Q11 النهائي (Q11_Arabic_Intervention_Bundles_Comprehensive_Audit_v1.0.0_2026-06-20) هيكلة الكتالوج المغلق للحزم. تتأثّر وحدة الحزم ومحرّك TAW وجميع المستهلكين الذين يقرؤون recommended_bundle_id.

ما الذي تغيّر:

  • 14 حزمة تدخّلية + 7 كائنات مُعاد تصنيفها غير تدخّلية (كانت 19 حزمة). تُصنَّف الكائنات السبعة الآن عبر الحقل الجديد BundleObjectType (9 قيم: INTERVENTION_BUNDLE / COMPOSITE_SEQUENCE_PLAN / COMPOSITE_INTERVENTION_BUNDLE / SUPPORT_MODULE / DECISION_CLARIFICATION_PROCESS / NON_INTERVENTION_OPTION / LIGHT_SUPPORT_ACTION / ROUTING_GUARD / FUTURE_INACTIVE_SUPPORT_OBJECT).
  • recommended_bundle_id أصبح قابلًا للإهمال (nullable). تحمل 7 صفوف MAP غير التدخّلية (MAP-000/001/002/003/018/019/020) القيمةَ NULL في هذا الحقل مضافًا إليها object_type ورمز routing_state_or_action_code (قرار الشريك D-015: الكائنات غير التدخّلية لا يجوز أن تشغل recommended_bundle_id). صفّ الحارس NO_BUNDLE_SYSTEM_GUARD كحزمة وهميّة متقاعَد؛ يحلّ محلّه رمز ROUTING_GUARD مع routing_state = BLOCKED_MISSING_EVIDENCE.
  • نطاقات التوزيع التراكمية عبر الدورة تحلّ محلّ النسب الثابتة لكل جلسة (D-003). أُلغي الشرط القديم sum==100 per session + anchor strictly largest CHECK. يُوصَف الجرعة الآن بنطاقات تخصيص عبر دورة التدخّل. وصفتان رئيسيتان معتمدتان (ورقة Q11 رقم 07): FLUENCY_WITH_MEANING (10–15% تهيئة ونمذجة / 60–70% قراءة موجّهة/متكرّرة مع تغذية راجعة للدقة مدمجة / 15–25% فحص معنى وانتقال)، وLANGUAGE_MEANING_BUILDING (45–55% محور لغوي مؤكَّد / 20–30% دعم ديناميكي واحد / 20–30% تطبيق سياقي وانتقال قريب).
  • VOCAB_SYNTAX_MORPH_BUNDLE يُقسَّم إلى 3 متغيّرات (VOCAB_DOMINANT / SYNTAX_DOMINANT / MORPH_DOMINANT) تحت bundle_family_id = LINGUISTIC_FEATURE_FAMILY.
  • TEXT_ACCESS_INTEGRATED_BUNDLE + COMPREHENSION_STRATEGY_BUNDLE مُعادان تصنيفهما إلى COMPOSITE_SEQUENCE_PLAN؛ MIXED_READING_LANGUAGE_BUNDLE إلى COMPOSITE_INTERVENTION_BUNDLE.
  • يتعامل TAW مع 4 مسارات غير تدخّلية (NON_INTERVENTION_OPTION / LIGHT_SUPPORT_ACTION / DECISION_CLARIFICATION_PROCESS / ROUTING_GUARD) عبر تسجيل رمز توجيه/إجراء — لا يُنشأ صفّ bundle_assignment لهذه المسارات.
  • أعمدة جديدة في bundle_definition: object_type, bundle_family_id, variant_code, runtime_status, anchor_selector, max_supporting_skills, asset_bridge_rule, grade_target_bridge_rule, immediate_progression_target, cycle_allocation_model.
  • حقول جديدة في bundle_assignment: object_type, family, variant, cycle_id, session_role, selected_anchor_skill_id, immediate_progression_target, grade_target_skill_id, relationship_map_version. تسعة أدوار جلسات مُعرَّفة: EXPLICIT_TEACHING / GUIDED_PRACTICE / RETRIEVAL_REVIEW / CONTEXT_APPLICATION / GRADE_TARGET_BRIDGE / SCAFFOLD_FADING / NEAR_TRANSFER / PROGRESS_CHECK / MAINTENANCE.
  • ISC-015 (ARABIC_FEATURE) مُتقاعَد. تُضاف التصنيفات الثلاثية للانتقال (proximal/near/far) إلى صفوف ISC المتبقّية (V5-012).
  • 6 فحوصات جودة جديدة QA_033–038: حزمة أساسية واحدة لكل دورة، المرحلة الفعّالة فقط، لا توجيه عبر حزمة وهميّة، لا استنتاج نوع الخطأ من ORF، لا توجيه عبر خاصيّة غير مفعّلة، ملاءمة المحتوى.

الهجرات: r12_d1_bundle_object_types + r12_d2_isc_transfer_split. المواصفة: 31-intervention-bundles.md (FR-IBC-1/2/3/4/9). المصدر: أوراق Q11 رقم 02/03/04/07/09/12 + القرارات D-001..D-015.

كتالوج مخطّطات الجلسات (WP-SBC-BE) — 2026-06-22

الخادم + المواصفة. كتالوج مخطّطات الجلسات المُؤلَّفة دون اتصال، من طرفه إلى طرفه، دون أي نموذج لغوي كبير. 17 عمليّة جديدة ضمن وسم session-catalog (يصبح الإجمالي المنشور 240 عمليّة).

  • المكتب الخلفي — POST/GET /api/session-blueprints/import (و/{batchId}) لاستيراد دفعة مخطّطات عبر بوّابة التحقّق (الاكتمال ← صحّة المفاتيح الأجنبية ← حدّ تغطية بنك الأسئلة ← سلامة اللغة ← منع التكرار؛ مسار كتابة وحيد، خامل عند تكرار البصمة)؛ POST /api/session-blueprints/{batchId}/approve يحوّل الصفوف المقبولة إلى تشغيليّة؛ GET /api/session-blueprints/{id} لجلب مخطّط واحد.
  • كتالوج المعلّم — GET /api/sessions/catalog لتصفّح الكتالوج التشغيلي والبحث فيه؛ GET /api/sessions/catalog/recommended يرتّب المخطّطات وفق إشارة حاجة RTI (مقروءة من الصفوف المخزّنة ذاتها التي يخصّص منها مسار الطالب؛ الأوزان من إعدادٍ مثبّت الإصدار؛ طلاب do_not_decide_yet يساهمون بصفر).
  • المُرشد (Wizard) — POST /api/sessions/from-blueprint وPATCH /api/sessions/{id}/edit وPOST /api/sessions/{id}/accept (توزيع ISM لكلّ طالب على قائمة الصف) وPOST /api/sessions/{id}/cancel وPOST /api/sessions/{id}/recipients/{studentId}/include (إعادة إدراج طالبٍ تخطّاه التوزيع — طلاب توقّف المحرّك يُتخطّون مع تدقيق، ولا يُسقطون أبدًا).
  • التسليم — POST /api/sessions/{id}/distribute-online يدفع جلسات كلّ طالب إلى قائمة التمرين؛ POST /api/sessions/{id}/generate-pdfs يولّد ملفّات PDF قابلة للطباعة لكلّ طالب مع رمز QR (كلّ رمز = رمز ربط لمثيل المهمّة المُقدَّمة)؛ GET /api/sessions/recently-generated وGET /api/sessions/{id} وGET /api/sessions/{id}/audit لقراءة الجلسات المولَّدة وسجلّ التدقيق.

يُنفّذ FR-SBC-1/2/3 و FR-SGE-5/6/7/12/13/14/15/16/17. تمّ التحقّق: فحوصات منع النماذج اللغوية ومسار الكتابة الوحيد والإلحاق فقط خضراء؛ openapi:check وopenapi:lint خضراء؛ بذرة المخطّطات النموذجية تُنتج 4 مخطّطات تشغيليّة، 0 مرفوض. الواجهة الأمامية تُشحن منفصلةً (WP-SGE-FE).

واجهة معالج مراجعة الاستيراد للمسؤول (WP-LMS-FE) — 2026-06-22

واجهة أمامية فقط — لا عمليّات واجهة برمجية جديدة (جميع المسارات شُحنت مع WP-LMS-BE). يُقدّم معالج الويب الإداري RTL من 5 مراحل (/admin/lms-import): ربط ← ربط المقرّرات ← مراجعة ← تأكيد ← منتهٍ. يُنفَّذ FR-LMS-13 (سير المعالج الكامل مع استعادة الحالة خلال 24 ساعة عند إعادة التحميل) وFR-LMS-14 (قائمة دور قابلة للتعديل — أساسي / مشارك / داعم — لكل معلّم في المقرّرات متعدّدة المعلّمين). يشمل قائمة الاتصالات وزرّ المزامنة الآن وجدول سجلّ عمليّات المزامنة وقطع الاتصال وإعادة الاتصال عند الإلغاء.

استيراد قوائم الطلاب — Google Classroom وOneRoster (WP-LMS-BE) — 2026-06-22

11 عملية جديدة تحت /api/lms/* ترفع الإجمالي المنشور إلى 221.

  • POST /api/lms/connections/:provider/oauth-start — بدء مصادقة Google Classroom عبر OAuth؛ يُعيد رابط إعادة التوجيه لمتصفّح المسؤول.
  • GET /api/lms/connections/:provider/oauth-callback — استقبال رمز التفويض من Google، والتحقّق من حالة الطلب، وتخزين الرمز المميّز، وإعادة التوجيه إلى معالج الاستيراد.
  • POST /api/lms/connections/:provider/token — رفع مجموعة ملفات OneRoster بتنسيق CSV أو بيانات اعتماد REST لإنشاء اتصال نشط مباشرةً.
  • GET /api/lms/connections — سرد جميع الاتصالات الخاصة بالمؤسسة مع الحالة وآخر وقت مزامنة.
  • DELETE /api/lms/connections/:id — قطع الاتصال وإيقاف المزامنة المجدوَلة.
  • GET /api/lms/:provider/courses — سرد المقرّرات المتاحة عبر الاتصال (مُخبَّرة 5 دقائق؛ ?cache=bypass لتجديدها). يتطلّب MANAGE_ROSTER.
  • POST /api/lms/:provider/mappings — حفظ ربط المقرّرات بصفوف أمل. يتطلّب MANAGE_ROSTER.
  • POST /api/lms/preview — إنشاء معاينة قراءة فقط للفروقات: مطابقة الهويّة بالمعرّف الخارجي أو البريد الإلكتروني المُحقَّق؛ يُعيد إجراءً لكل سجلّ create | update | conflict | skip مع ملخّص إجمالي. لا تُكتَب أي بيانات في جداول المستخدمين. صلاحية المعاينة 24 ساعة.
  • PATCH /api/lms/preview/:previewId/rows/:rowId — حفظ قرار حلّ التعارض (accept_lms | keep_amal | skip_row) لسجلّ واحد.
  • POST /api/lms/commit/:previewId — تأكيد المعاينة في معاملة Postgres واحدة: إنشاء المستخدمين، وتسجيلهم في الصفوف، وتعيين أدوار المعلّمين، وإنشاء رموز الدخول، وإضافة سجلّات UserExternalIdentity(source=roster_import) (لتفعيل تسجيل الدخول عبر Google تلقائيًّا). تُعيد { created, updated, skipped, conflicts_remaining }. ملغاة الأثر عند الإرسال المتكرّر. تُعيد 422 إذا وُجد تعارض غير مُحلول.
  • GET /api/lms/sync-runs — سجلّ المزامنة مرقَّم الصفحات للمؤسسة.
  • POST /api/lms/connections/:id/sync-now — تشغيل مزامنة فورية؛ يُعيد 202 { syncRunId }.

تتطلّب جميع المسارات requireAuth. مسارات إدارة الاتصال تتطلّب MANAGE_LMS_CONNECTIONS؛ مسارات قوائم الطلاب تتطلّب MANAGE_ROSTER. المورد غير المرتبط بالمؤسسة أو المستخدم يُعيد 404 دون الإفصاح عن وجوده.

دعم تعدّد المعلّمين (B.4). عند وجود أكثر من معلّم في مقرّر لنظام التعلّم، يُنشئ التأكيد سجلّ ClassTeacher واحدًا لكل معلّم (الأوّل أساسي، وسواه مشارك). لا يُعدَّل Class.teacherId أبدًا.

إلغاء رمز المصادقة. أي استجابة 401 أو 403 من مزوّد الخدمة تضبط connectionStatus=revoked وتوقف المزامنة المجدوَلة وتُرسل إشعار lms_connection_revoked لجميع مسؤولي المؤسسة وتُضيف سجلّ LmsSyncRun{status:error}. يُعيد المسؤول الاتصال من صفحة الاتصالات.

بوّابة بيانات أولياء الأمور (Q-LMS-5 🔴). استيراد بريد أولياء الأمور من Google Classroom مُغلَق افتراضيًّا (LMS_GUARDIAN_IMPORT_ENABLED=false) حتى اجتياز المراجعة القانونية للاحتفاظ بالبيانات. لا يدعم OneRoster استيراد بيانات أولياء الأمور في الموجة الأولى.

تسجيل الدخول عبر Google — الدخول الموحّد (WP-SSO-BE) — 2026-06-22

أصبح تسجيل الدخول باستخدام بروتوكول OAuth 2.0 من Google (تدفّق رمز التفويض + PKCE) متاحًا للمستخدمين البالغين (المعلّمين، والمسؤولين، ومديري المدارس) والطلاب المرتبطين بسجلّ الحضور. 3 عمليات جديدة ترفع الإجمالي المنشور إلى 206.

  • GET /api/auth/google/start — تُعيد رابط إعادة توجيه OAuth إلى Google. تُنشئ صفًّا واحدًا للاستخدام المرّة الواحدة GoogleOAuthState (صالح 10 دقائق) يحمل حالة CSRF ومُحقَّق PKCE.
  • GET /api/auth/google/callback — تستقبل رمز التفويض من Google، وتتحقّق من الحالة، وتُحقَّق من رمز الهويّة، وتُحلّ الهويّة عبر سلسلة أولويّة ثنائية (المعرّف الفرعي ← البريد الإلكتروني المُحقَّق)، ثم تُعيد توجيه المتصفّح إلى الواجهة الأماميّة بـ ?code= صالح لمدة 60 ثانية للاستخدام المرّة الواحدة. لا تظهر الرموز المميّزة أبدًا في رابط إعادة التوجيه.
  • POST /api/auth/google/exchange — يستبدل رمز الجسر بزوج رموز قياسي { accessToken, refreshToken, tokenType }. يُعلَّم الرمز مُستهلَكًا عند أول استخدام؛ الرموز المُعادة أو المنتهية الصلاحية تُعيد 401.

يتمكّن الطلاب من تسجيل الدخول عبر Google فقط عند وجود رابط UserExternalIdentity من نوع roster_import أنشأه المسؤول مسبقًا (لا يُسمح بالتسجيل الذاتي). يتحكّم حقل Organization.allowedGoogleDomains بنطاقات Google Workspace المقبولة؛ إذا كانت القائمة فارغة يُقبل أيّ حساب Google. تتجاوز حسابات المسؤولين العامّين (null-org SUPER) هذه البوّابة تلقائيًا.

إعادة تسمية مؤشّر الالتباس — AR_LETTER_CONFUSION_FLAG ← AR_ORTHOGRAPHIC_CONFUSION_FLAG (R12 / Q4) — 2026-06-22

أُعيدت تسمية مؤشّر التباس الحروف العربية ليُطابق اسمُ القيمة دلالتَه المعتمدة سابقًا (تأكيد الشريك 2026-06-19 حصره في الالتباس البصري/الإملائي فقط — لا السمعي). ترحيلٌ يحفظ البيانات عبر ALTER TYPE "SubFlag" RENAME VALUE (r12_rename_orthographic_flag)؛ تحتفظ الصفوف القائمة بقيمتها تحت الاسم الجديد. لا تغيير في السلوك — اشتقاق المؤشّر ونطاقه وتوجيه البروفايل لاحقًا دون تغيير. (محرّك المؤشّرات متعدّد المراحل الأوسع في Q4 يبقى بندَ عملٍ منفصلًا مجدولًا.)

خريطة العلاقات بين المهارات (R12 Tier-E / Q7) — 2026-06-21

الخادم + المواصفة. تُشحَن خريطة علاقات المهارات (الشريك Q7) بوصفها مخطّطًا فرعيًا عالميًّا استشاريًّا فقط. تُبذَر 195 علاقة + 413 رابط تشغيل عبر 11 جدول إعداد عالمي جديد (skill_rel_type / subtype / runtime_use / trigger / type_runtime_map / applicability / group / skill_relationship / runtime_link / skill_coverage / qa_rule)، خلف بوّابة استيراد من 22 قاعدة وقت البذر.

  • NO_BLOCK / measurement_effect = NONE. الخريطة توثيقيّة فقط — غير مربوطة باختيار البنود أو التقييم أو أي مسار قرار. يُفشِل الحارس lint:skill-rel-not-wired البناءَ إذا استوردتها أي وحدة قرار.
  • المواصفة: docs/product/prds-v2/10-skills-and-standards/12-skill-relationship-map.md. المصدر: الشريك Q7. الهجرة: r12_e_skill_relationship_map.

المهارات — MORPH-C01 وأهليّة CBM (R12 Tier-A / Q9) — 2026-06-21

الخادم + المواصفة. يرتفع جدول المهارات الرئيسي من 79 → 80 مهارة: تُضاف MORPH-C01 تمييز المفرد والجمع وفق مذكّرة الشريك Q9. أصبحت أهليّة CBM خاصيّةً صريحةً لكل مهارة — محصورة بـنص ORF فقط، فلا تكون DWR-A03 / DWR-A05 مؤهَّلتَين لـ CBM.

  • تؤكّد البذرة skills_master_table = 80 (76 فعّالة = 80 − LISTEN×3 − WR-SP-F03). المواصفة: 11-skills-taxonomy.md. المصدر: مذكّرة الشريك Q9 بتاريخ 2026-06-21.

المعايير — معايير ORF حسب النافذة (R12 Tier-A / Q8) — 2026-06-21

الخادم + المواصفة. تكتسب طبقة المعايير بُعدَ نافذة التقييم الاختياري في الحلّ، وعلاماتٍ مرجعيّة لقابليّة تطبيق ORF.

  • AssessmentWindow {BOY/MOY/EOY} + 5 أعمدة بيانات وصفيّة جديدة على BenchmarkProfile (benchmarkStatus, sourceStrength, requiresRecalibration, minimumAccuracyPct, orfApplicability). استُخرجت قِيَم قطع ORF الحقيقية من الشريك: الأردن 46 / فلسطين 33. تُنتج البذرة الآن 55 صفًّا معياريًّا (18 صفًّا مستقلًّا عن النافذة من الشريك + 24 صفّ ORF حسب النافذة + 13 صفّ احتياطي __GLOBAL__).
  • حلّ احتياطي تمثيليّ لنافذة EOY (findWithWindowFallback)؛ مسار HTTP …/resolve أعمى عن النافذة حاليًّا (متابعة Tier B) ويحلّ بصرف النظر عن النافذة. تُعيد علامتا NOT_APPLICABLE / OPTIONAL_BASELINE_NO_CUT (الصف الأول + الصف الثاني BOY = غير قابل للتطبيق) علامةً مُحدَّدة النوع — لا حُكم Meets/Below أبدًا.
  • المواصفة: 12-benchmarks-and-country-config.md §FR-STD-7/8. الهجرة: r12_a_windowed_orf_benchmarks.

المعايير — قاموس مؤشّرات المنهج لكل صفّ، للمواءمة فقط (R12 Tier-A / Q9) — 2026-06-21

الخادم + المواصفة. تُبذَر 51 مؤشّر منهج لكل صفّ (الأول:12 / الثاني:13 / الثالث:13 / الرابع:13) في 3 جداول عالمية جديدة (curriculum_kpi_dictionary, curriculum_kpi_to_skill_map, curriculum_kpi_country_map).

  • ضمان حوكمة المواءمة-فقط. يحمل كل صفّ decisionWeight = 0 (قيد DB CHECK) + runtimeRole = ALIGNMENT_ONLY. يمنع الحارس الجديد lint:kpi-alignment-only أي وحدة محرّك قرار من قراءة الجداول الثلاثة (V-3). تُتخطّى المهارات غير الفعّالة ومهارات LISTEN من خريطة المهارات.
  • المواصفة: 12-benchmarks-and-country-config.md §FR-STD-9/10. الهجرة: r12_a_curriculum_kpi_dictionary.

محرّك القرار — تصعيد العجز إلى Severe عبر المسار B (R12 Tier-B / Q3) — 2026-06-21

الخادم + المواصفة. يكتسب تجميع المجالات الكبرى (L5 DSM) مسارَ تصعيدٍ ثانيًا إلى Severe. لا تكون Severe إطلاقةً مباشرةً من DSM، ولا قائمةً على العدّ، ولا على المئينيّات — تُنتَج فقط عبر مسارَي تصعيد:

  • المسار A (قائم) — شدّة البوّابة ≥ DTH-SEV-01 (DSM-04).
  • المسار B (جديد) — مغذٍّ من coherent_domain_weakness / broad_related_domain_concern / gateway_driven_domain_concern معدّل عجزه المرجَّح الخام weightedDeficitRate ≥ DTH-DEF-03 (50%) بأدلّة صالحة يتصعّد إلى Severe. إعادة ضبط DTH-DEF-03 تُزيح الآن حدّ Below↔Severe، لا تصنيف القلق الواسع وحده.
  • المواصفة: 21-skill-status-engine.md FR-SSE-11 + 22-macro-domain-rollup.md §4. المصدر: الشريك Q3 R12.

التزام التدخّل — دورة حياة خارج المسار + حظر التخفيض (R12 Tier-B / Q2) — 2026-06-21

الخادم + المواصفة. تكتسب طبقة الالتزام دورةَ حياة «خارج المسار» وتُحكِم بوّابة الحركة.

  • دورة حياة خارج المسار. الخطّة التي تمرّ بها 3 أسابيع تعليمية دون تسليم تدخل حالة «خارج المسار» المتتبَّعة على intervention_track_status الجديد. الالتزام دون 80% يُنتج حُكم invalid_due_to_implementation_gap.
  • TM_BLOCK_01 يحظر أيضًا التخفيض (لا التصعيد وحده) عند الالتزام المنخفض/المجهول — «الخطّة غير المُنفَّذة» لم تعد تُحرّك درجة الطفل في أيّ اتجاه.
  • المواصفة: 35-fidelity-tracker.md + 34-rti-alerts.md. الهجرة: r12_b_intervention_track_status.

CBM — أرضية اتجاه من 3 نقاط قابلة للمقارنة + بيانات قابليّة المقارنة (R12 Tier-B / Q5) — 2026-06-21

تغيير كاسر نهائي من الشريك. تنخفض أرضية اتجاه CBM من 4 → 3 نقاط قابلة للمقارنة (GrowthTrendRule.minimumComparablePointsForStrongTrend، الافتراضي 3، مدفوعة بالإعداد ومثبّتة V-6) — وهذا يُلغي قاعدة v5 ذات الأربع نقاط. دون الأرضية → insufficient_points.

  • بيانات قابليّة المقارنة (§6) مُضافة لكل اختبار على cbm_scores (comparabilityGroupId, probeType, assessmentWindow, difficultyBand, diacriticsLevel, timingSeconds = 60, administrationMode = TEACHER_LED). مفتاح قابليّة المقارنة GSR-04 يمنع الآن خطّ اتجاه واحد يجمع قائمة كلمات بنصّ متّصل، أو نصًّا مشكولًا بغير مشكول.
  • ضمانات محفوظة: لا قرار من نقطة واحدة؛ 3 نقاط وحدها لا تُفشل خطّة ولا تُحرّك درجة تلقائيًّا (بوّابات GSR + خارج-المسار/الالتزام). يُبذَر صفّ الإعداد الجديد growth_trend_rule (القيمة=3) مع الكتالوج.
  • المواصفة: 33-fluency-measurement.md FR-CBM-4 + §6. الهجرة: r12_b_cbm_trend_floor.

الإحماء الذهني — للتدريب فقط، دقيقة واحدة (R12 Tier-C / Q10) — 2026-06-21

تغيير نهائي من الشريك يمسّ وحدة الإحماء الذهني (61-cognitive-warmup.md). ثلاثة تغييرات في سلوك واجهة warmup:

  • POST /api/warmup/sessions يتطلّب الآن sessionType — TRAINING أو INTERVENTION_PRACTICE فقط. أي قيمة أخرى (مثل سياق تقييمي) تُرفض 422 (فشل آمن). لا يعمل الإحماء قبل أي تقييم (BOY/MOY/EOY/Screening/ORF/CBM/confirmatory).
  • مدة ثابتة 60 ثانية — تُستبدل خطة الـ 3–5 دقائق متعددة المراحل بوحدة واحدة محدودة بـ 60 ثانية؛ يُنهي المحرّك الجلسة تلقائيًا عند بلوغ الحد (MAX_WARMUP_MS = 60_000). لا يظهر أي عدّاد تنازلي للطفل.
  • تسليم الإعدادات النهائية لـ COG-05 (المطابقة) + COG-06 (التتبّع البصري) وتفعيلها — 8 صفوف جديدة في WarmupGradeConfig تحمل أعداد العناصر القابلة للقراءة آليًا (numberOfVisualElements, pairCount, movingObjectsCount, targetCount, distractorCount, pathNodesCount, crossingCount, occlusionCount, speedChangeCount) إضافةً إلى templateContractId (TPL-COG05-*/TPL-COG06-*). يَبذُر الكتالوج الآن 32 إعدادًا فعّالًا (بدلًا من 24 فعّالًا + 8 غير فعّالة).

دون تغيير: لا يزال الإحماء لا يُغذّي θ / الإتقان / XP (G-ISO)؛ scored=false / decision_weight=0 ولا يُحتسب ضمن جرعة التدريب اللغوي. تُضيف الهجرة r12_c_warmup_60s نوع WarmupSessionType، وعمود sessionType على warmup_session، وأعمدة أعداد عناصر COG-05/06 على warmup_grade_config.

واجهة التحفيز التعليمي (WP-14-FE) — 2026-06-21

واجهة أمامية فقط، لا مسارات جديدة في الخادم. تستهلك واجهتَي WP-14-BE المشحونتين (gamification وleaderboard). تُطلق ستّة أسطح عبر أربع شخصيّات.

  • ملفّ الطالب الذاتي (S1) (/student/me): يرى الطالب رصيد نقاط النموّ ومستوى الشخصية والسلسلة اليومية (الحالية والأطول) وجدار الشارات المؤلَّف من 15 خانة (المكتسَبة بالألوان، والمقفلة كظلال مع تلميح). ملفّ الطالب لا يحمل بيانات أقران، ولا توجد صفحة لوحة صدارة تحت تطبيق الطالب، فلا مجال لظهور أيّ مقارنة أو ترتيب.
  • احتفال فتح الشارة (S2): طبقة غير معيقة تُعلن فتح كلّ شارة جديدة (اسمها بالعربية وأيقونة جائزة متحرّكة). تُقارَن رموز الشارات المجلوبة حديثًا بآخر مجموعة محفوظة في ذاكرة المتصفّح، فتظهر الطبقة مرّةً واحدة لكلّ شارة ولا تتكرّر بعد إعادة التحميل (Q-SYNC-10).
  • لوحة نموّ الصفّ (T1) (/teacher/class/[classId]/leaderboard): يرى المعلّم أعداد أحداث الإتقان وتقدّم المستوى لكلّ طالب في صفّه، مرتّبةً حسب النموّ، مع تفصيل لكل نوع حدث. تأتي عناوين الأعلى والمرشّحين للدعم من الخادم (framing.topLabelAr / framing.bottomLabelAr)؛ الواجهة لا تخترع مصطلحات الترتيب. أدوات التحكّم بالعرض (بأحداث الإتقان / بتقدّم المستوى) والنافذة الزمنية (7 / 14 / 30 يومًا) تُحفَظ في حالة الرابط.
  • لوحة نموّ جميع الصفوف (T2) (/teacher/leaderboard): نفس جدول النموّ مجمَّعًا عبر جميع صفوف المعلّم، مع رقائق تجميعيّة لكل صفّ تُوصِل إلى T1.
  • لوحة نموّ المدرسة (P1) (/principal/leaderboard): نفس السطح بنطاق جميع صفوف المدرسة، متاحٌ لشخصية مدير المدرسة فقط (يُعيد 403 لأي دور آخر).
  • إلغاء الشارة (T3): يُطلَق من قائمة شارات الطالب داخل صفحة تفاصيل الطالب للمعلّم. يختار المعلّم الرمز المضبوط الوحيد (Gam_Award_Invalid_05)؛ لا يوجد حقل نصّ حرّ. تبقى الشارات الملغاة ظاهرةً بشريطة «أُلغيت» (مرئيّة للمراجعة، لا تُخفى، V-6).
  • لوحة مراجعة المسؤول وإعادة التشغيل (A1) (/admin/gamification): استعلام بمعرّف الطالب والنطاق الزمني لاستعراض تدفّقات أحداث الإتقان ومعاملات النقاط والشارات، ثمّ تشغيل فحص انجراف إعادة التشغيل (V-6) الذي يُعيد اشتقاق الأرصدة والشارات من السجلّ الثابت ويُبلّغ عن أيّ حقل يختلف عن القيمة الحالية.
  • حقل BE إضافيّ (تمّ حلّ OQ-RESCIND-ID). يحمل BadgeDto الآن الحقلَين studentBadgeId وstatus لمستدعي المعلّم ومدير المدرسة والمسؤول؛ يُحذفان من استجابة الطالب والوالد. يعكسهما amal-api.yaml (يُعرَض تلقائيًا في مرجع الواجهة البرمجية للبوّابة). عدد العمليات ثابت: 202.

التحقّق: Playwright e2e عبر أجهزة الهاتف واللوح والحاسوب والعارض، مع تأكيد لغة النموّ في كلّ مكان وغياب نصوص ترتيب الأقران على أسطح الطلاب وبوّابة رمز الإلغاء وفحص انجراف إعادة التشغيل. فحص رسم الاستيراد AC-GAM-2 واختبارات لقطة الرموز النصية جميعها خضراء.

إعدادات المعلّم والمشرف (WP-SETTINGS-FE) — 2026-06-21

واجهة أمامية فقط — دون أي تغيير في الخادم أو المواصفة. تُغلق مسارَي التنقّل المعطّلَين الإعدادات (/teacher/settings و/manager/settings) بصفحتَي حساب وتفضيلات بسيطتَين لكن حقيقيّتَين على الواجهة الموحَّدة للبالغين. كلّ قسم مدعوم بواجهة مشحونة أو بتفضيل محفوظ على الجهاز؛ لا شيء مُختلَق.

  • الحساب (للقراءة فقط): الاسم والدور والبريد والمؤسسة وعدد الصفوف (للمعلّمين) من GET /api/auth/me. لا إدخال لكلمة المرور أو بيانات الاعتماد، ولا إجراءات حذف للحساب — بل توجيه «تواصل مع مسؤول النظام في مؤسستك» بدلًا من ذلك.
  • إمكانية الوصول: مفتاحا التباين العالي والخطّ المناسب لعسر القراءة نفساهما المتاحان في الترويسة، معروضَين كقسم في الإعدادات. يقود السطحان تفضيلًا واحدًا محفوظًا على الجهاز، فيبقى التبديل في أيّهما متّسقًا.
  • الإشعارات: عدد الإشعارات غير المقروءة للقراءة فقط من GET /api/notifications/unread-count، مع تنويه بأن الإشعارات تظهر من جرس الترويسة. لا توجد نقطة كتابة لتفضيلات الإشعارات، لذا لم تُختلَق أي تفضيلات — القسم حالة للقراءة فقط.
  • تسجيل الخروج: POST /api/auth/logout، ثم العودة إلى صفحة الدخول العامّة — أوّل سطح لتسجيل الخروج في التطبيق.
  • ملاحظات (نواقص الخادم): لا نقطة كتابة لتفضيلات الإشعارات؛ ولا آلية تبديل لغة التطبيق (لذا لم يُبنَ قسم اللغة)؛ ولا تحمل حمولة الهويّة حقل رمز دخول.

تم التحقّق: فحص الأنواع والـ lint والبناء الإنتاجي كلّها نظيفة (المساران موجودان)؛ وPlaywright e2e 4/4 على الحاسوب واللوح، مع تأكيد ظهور أقسام الحساب وإمكانية الوصول والإشعارات، وعمل مفتاح إمكانية الوصول من الإعدادات، وصفر أخطاء في الطرفيّة. واجهة عربية أوّلًا من اليمين إلى اليسار، وسمة فاتحة.

مسارات المعلّم الثانوية (WP-TEACHSEC) — 2026-06-21

واجهة أمامية فقط — دون أي تغيير في الخادم أو المواصفة. تُغلق مسارات تنقّل المعلّم الثلاثة المعطّلة بإضافة نقاط الدخول العابرة للصفوف: عدسة «كلّ صفوفي دفعةً واحدة» التي تعجز عنها الشاشات المرتكزة على صفّ واحد. وكلّها تستهلك واجهات مشحونة ومحصورة بصفوف المعلّم (ClassTeacher).

  • طلابي (/teacher/students): كلّ طلاب المعلّم عبر جميع صفوفه في قائمة واحدة قابلة للمسح السريع — الاسم، والصفّ، وكلمة حالة أضعف مجال، وشارة كثافة الدعم، وعلامة التنبيه المفتوح — مرتّبة بحيث يظهر مَن يحتاج الانتباه أوّلًا، مع مُرشِّح حسب الصفّ. يفتح كلّ صفّ ملفّ الطالب الموجود.
  • متابعة التقدّم (/teacher/progress): إشارات المتابعة المفتوحة عبر صفوف المعلّم — تنبيهات التراجع المفاجئ (مصاغة للمراجعة، لا بوصفها إخفاقًا) وإشارات اتجاه طلاقة القراءة — مربوطة بكلّ طالب وموصِّلة مباشرةً إلى مراجعة الخطّة.
  • خطط الدعم (/teacher/plans): كلّ خطط الدعم المُفعَّلة عبر صفوف المعلّم، مع تقدير الالتزام والتوصية وشارة بوّابة «أكملي الجرعة أوّلًا»، وتفتح تفاصيل الخطّة الموجودة.
  • الالتزام بضوابط المعلّم. لا نسبة مئوية إجماليّة واحدة في أيّ مكان (كلمات حالة وأعداد فقط)؛ ولغة نموّ في كلّ النصوص؛ ولا تظهر سوى صفوف المعلّم وطلابه. مُركَّبة في الواجهة الأماميّة عبر استدعاء القراءات المشحونة لكلّ صفّ (لا توجد نقطة تجميع بعد).

تم التحقّق: Playwright e2e 6/6 على الحاسوب واللوح، مع تأكيد التجميع العابر للصفوف، وغياب النسبة المئويّة، ولغة المراجعة، وبوّابة الالتزام، وصفر أخطاء في الطرفيّة لكلّ مسار؛ ولم تتأثّر اختبارات المعلّم القائمة.

واجهة التزويد الإداري (WP-ADMINFE) — 2026-06-21

واجهة أمامية فقط، دون أي تغيير في الخادم أو المواصفة. تستهلك واجهتَي WP-A2 (البنية المؤسسية) و WP-A3 (المستخدمين) المشحونتين. تَنزِل ثلاثة أسطح إدارية على واجهة الكبار، تمنح المسؤول كل ما يلزم لتأسيس بنية المؤسسة وأفرادها.

  • المؤسسات (/admin/organizations): صفحة تنقّل تدريجي واحدة — المؤسسات → المدارس → الصفوف — عبر الكشف داخل الصفحة. يجري الإنشاء والتحرير في نوافذ حوارية في كل مستوى. تُحذف المؤسسات حذفًا مؤقّتًا؛ أمّا المدارس والصفوف فلا تُحذف إلّا وهي فارغة، ويعرض حذفُ غير الفارغ إرشادًا واضحًا بنقل الأعضاء أوّلًا بدل الحذف المتسلسل المُتلِف.
  • المستخدمون (/admin/users): قائمة مستخدمين قابلة للتصفية (حسب الدور) مع الإنشاء، ويتكيّف النموذج مع الدور المختار (طالب، معلّم، ولي أمر، مدير مدرسة، مشرف، مسؤول). يكشف إنشاء طالبٍ عن رمز دخوله لمرّة واحدة فقط. يمكن إسناد صفوف المعلّمين عبر جدول الربط متعدّد الصفوف.
  • الصلاحيات (/admin/roles): مصفوفة الأدوار × الصلاحيات للعرض فقط، منسوخة من تعريفات الأدوار في المنصّة للرجوع إليها. وهي ثابتة في الموجة الأولى وغير قابلة للتعديل من الواجهة.
  • العربية أوّلًا في كل مكان. كلّ اختيار يجب أن يكون من مجموعة محدّدة (البلد، الصفّ، الدور، الرتبة، اللهجة) هو قائمة منسدلة مغلقة، لا نصًّا حرًّا. سمة فاتحة، ونوافذ حوارية بدل الألواح المنزلقة.

تم التحقّق: Playwright e2e (تنقّل المؤسسات والإنشاء، قائمة المستخدمين وتصفيتها وإنشاؤها، مصفوفة الصلاحيات) على عرضَي الحاسوب واللوح، دون أيّ أخطاء في الطرفية.

إعدادات إمكانية الوصول — تباين عالٍ وخط لعسر القراءة (WP-A11YTOG) — 2026-06-21

واجهة أمامية فقط، دون أي تغيير في الخادم. إعدادان لإمكانية الوصول محفوظان على الجهاز يُلبّيان البندين FR-ACC-4 (التباين العالي) وFR-ACC-9 (خط مناسب لعسر القراءة)، يظهران من قائمة إمكانية الوصول في ترويسة واجهة البالغين.

  • وضع التباين العالي يبدّل سمة واحدة على المستند (<html data-contrast="high">) تُعيد تعريف ألوان رقاقات الحالة إلى أزواج تباين بنسبة ≥7:1 — فتتغيّر ألوان كل الرقاقات والشارات والحدود والنصوص الباهتة دفعةً واحدة، دون عمل على مستوى كل مكوّن. ويمكن إضافة ترميز بالأنماط (تظليل مائل / نقاط / تقاطع) بلا اعتماد على اللون وحده لمن لديهم عمى ألوان.
  • الخط المناسب لعسر القراءة يبدّل وجه الخط العربي ويزيد التباعد بين الكلمات وارتفاع السطر. ولا يضيف تباعدًا بين الحروف عمدًا، لأن ذلك يكسر اتّصال الحروف في الخط العربي المتّصل. أمّا الوجه المعتمَد من الشريك فما زال بانتظار قراره (🚩 OQ-ACC-5) ويُبدَّل عبر متغيّر CSS واحد دون تغيير في الشيفرة.
  • الحفظ دون ومضة. يُحفظ الإعدادان على الجهاز ويُستعادان عبر نص تمهيدي متزامن قبل رسم الصفحة، فيبقيان بعد إعادة التحميل دون ومضة للمظهر الافتراضي. وعلى الجهاز المشترك في الصف تُفعّلهما المعلّمة أو ولي الأمر مرّة واحدة، فترثهما واجهة الطالب الغامرة تلقائيًا (وأُجِّلت قائمة مخصّصة داخل واجهة الطالب).

التحقّق: اختبارات Playwright الشاملة — تفعيل التباين العالي يعيد تلوين رقاقة حالة ويجتاز فحص axe-core بصفر مخالفات WCAG-AA؛ ومفتاح عسر القراءة يغيّر الخط والتباعد؛ ويبقى الإعدادان بعد إعادة التحميل. مجموعة إمكانية الوصول كاملةً (75 اختبارًا) ناجحة عبر الهاتف واللوح والحاسوب والعارض دون تراجع.

عارض سجلّ التدقيق الإداري (WP-AUDITLOG) — 2026-06-21

عمليّة واحدة جديدة تحت وسم audit الجديد، ليرتفع إجمالي العمليّات المنشورة إلى 203 عمليّات.

  • GET /api/admin/audit-log — قائمة موحَّدة للقراءة فقط لأحداث أمان المنصة، مرتَّبة زمنيًا عكسيًا ومقسَّمة على صفحات. للمسؤول فقط (VIEW_QA_REGISTRY)؛ محدودة بنطاق المستأجر لكل جدول. تحمل الاستجابة نوع الحدث ومعرّف المنفّذ والطابع الزمني ومؤشر طول القيمة فقط؛ لا عناوين IP ولا وكلاء المستخدم ولا القيم المُحاوَل إرسالها. قابلة للتصفية حسب نوع الحدث والمنفّذ والنطاق الزمني؛ مقسَّمة بـlimit / offset. يرى المسؤول فائق الصلاحية (null-org) جميع المؤسسات. قراءة المسؤول فائق الصلاحية تُلحق صفًّا واحدًا في SuperAdminBypassLog (القراءة ذاتها مُدقَّقة)؛ قراءة المسؤول العادي لا تُلحق شيئًا.

تُضيف صفحة عارض الويب الإدارية (/admin/audit-log) شريط تصفية وحوار تفصيلي وتقسيمًا على صفحات.

إحصاءات نطاقات مدير المدرسة ومتابعة النموّ (WP-PRN-COMPLETE) — 2026-06-21

لا مسارات جديدة؛ المسارات الثلاثة التي كانت بيانات مؤقتة باتت ترجع بيانات حقيقية. عدد العمليّات ثابت: 203 عمليّات.

  • GET /api/principal/schools/{id}/overview — مؤشرات المنهج من صفوف domain_status_snapshot الفعلية: أعداد الطلاب بكل حالة لكل نطاق، ومؤشر صحة محو الأمية المدرسي المشتقّ من تلك الأعداد. لا معرّفات طلاب ولا أسماء في الاستجابة؛ ولا نسب مئوية (V-3).
  • GET /api/principal/schools/{id}/heatmap — مصفوفة الصف مقابل المؤشر بأعمدة عربية فقط؛ الإدخالات غير المقيَّمة مستثناة من الأعداد.
  • GET /api/principal/schools/{id}/growth — أعداد الحالات بحسب النافذة الزمنية مع حركة النافذة مقابل النافذة (تحسّن / تراجع / ثبات). النطاق غير المصنَّف مستثنى من الحركة. الاستجابة متطابقة عند التكرار (V-6).

واجهة سير عمل تفعيل المعلّم (WP-TAW-FE) — 2026-06-21

واجهة أمامية فقط، دون أي تغيير في الخادم أو المواصفة. معالج «القرار ثم التدخّل» الذي يُتيح واجهة WP-TAW-BE لسير العمل للمعلّمين. خمس مراحل تنقل المعلّمة من قراءة التوصيات لكل طالب حتى تأكيد الخطط المُفعَّلة؛ ثم تتبع كل تعيين نشط شاشةُ مراقبة.

  • معالج التفعيل (/teacher/class/[classId]/activate): خمس مراحل متتالية: لوحة التوصيات (توصية حزمة لكل طالب مع سبب مكتوب وفق القواعد ونقطة قوة موثّقة)، ثم التجميع الذكي (تجميع الطلاب الذين يمكنهم مشاركة خطة واحدة)، ثم معاينة السقالات (مزيج مستوى الدعم، قابل للتعديل من المعلّمة لكل طالب)، ثم مراجعة التفعيل (أسلوب التسليم والجرعة ونوع المهمة مع شرح لمرّة واحدة عن سبب التوصية)، ثم التأكيد (مجمّع أو فردي). تُحفظ حالة المسودة عبر الجلسات (TTL 7 أيام على الخادم).
  • مراجعة الخطة والمراقبة (/teacher/class/[classId]/plans/[assignmentId]): بطاقة الالتزام وأداة المراقبة وتدفقات قرار ما بعد التفعيل (الإبقاء / التخفيض / التصعيد / الحظر على ضعف الالتزام).
  • ثلاثة ضمانات غير قابلة للتجاوز. عدم كفاية الأدلّة: يُعطَّل التفعيل ولا يُتاح سوى خيار «طلب مزيد من البيانات». رصد تراجع مفاجئ: تُفتح نافذة مراجعة؛ لا تُوقَف الخطة تلقائيًا ولا تُفشَل. غياب ملفّ مستقرّ: يُستبعَد الطالب من التجميع. كل ضمانة تستلزم إجراءً صريحًا من المعلّمة قبل أن يتابع المعالج.
  • المعلّمة تتّخذ كل قرار (V-12). المعلّمة تقرّر في كل خطوة. تستخدم حقول الأسباب القائمة المضبوطة ذات التسعة رموز، لا نصًا حرًا. لا تظهر التسميات الداخلية أو معرّفات المستوى أو الدرجات على أي سطح مرئي للطالب.

تم التحقّق: Playwright e2e 16/16 على عروض الهاتف واللوح والحاسوب وعارض الصفّ، مع تغطية المراحل الخمس للمعالج والمسارات الثلاثة للضمانات.

واجهة الحصّة المباشرة (WP-18-FE) — 2026-06-21

واجهة أمامية فقط — دون أي تغيير في الخادم أو المواصفة. تستهلك واجهة sync المشحونة من WP-18-BE. تَنزِل ثلاثة أسطح مباشرة على أصداف WP-RBL.

  • لوحة قيادة المعلّم على المسار /teacher/sync (واجهة الكبار): ينشئ المعلّم حصّةً مسوّدةً لصفّ → يحصل على رمز صفّ رقمي يقرؤه بصوتٍ عالٍ → يبدأ (بوّابة سلامة اللغة) → يقود قائمة الأنشطة بأوامر تحكّم مُتسامحة مع التكرار (تقديم / إيقاف مؤقّت / استئناف / تخطّي / إنهاء). يعرض العرضُ المباشر أعدادًا إجماليّةً فقط (المنضمّون / المُجيبون / المنتظرون) — لا تفاصيل لكلّ طالب (FR-SYNC-9).
  • شاشة استجابة الطالب على المسار /student/sync (عالم الطالب الغامر): ينضمّ عبر رمز الصفّ الرقمي (للمسجَّلين فقط)، يرى الخطوة الحالية، يُجيب على جهازه. تُعيد استعادةُ التخزين المحلّي (Q-SYNC-10) الطالبَ إلى الخطوة المباشرة ذاتها بعد التحديث / القفل / تبديل التطبيق / انقطاع الشبكة.
  • شاشة العرض المشتركة على المسار /projector/sync (ملء الشاشة، دون بوّابة شخصية): النصّ المشترك، ورمز الانضمام الكبير، والأعداد الإجمالية فقط — دون أي تفاصيل داخلية لكلّ طالب (FR-CLIENT-10).
  • نمط المجموعات: إرسال توافقي يقوده القائد فقط؛ يتابع غيرُ القادة (الإرسال مُعطَّل).
  • استطلاع REST فقط (Q-SYNC-1 / B.8) — دون WebSocket / SSE / WebRTC. يضاعف التراجعُ لتوفير الطاقة الفترةَ عند الاستطلاعات الفارغة (بحدٍّ أقصى 10ث) ويستطلع فورًا عند العودة إلى التبويب.
  • مؤجَّل: شاشة العرض المخصّصة (FR-SYNC-PRJ-1..5) وملاحظة القراءة الجهرية (FR-SYNC-12) — في مرحلةٍ لاحقة؛ تُرجِع منافذ الإعداد/الالتزام لديها 503 حتى تُشحَن خدمتا توليد الجلسات والمسح.

جسر إسقاط لقطات محرّك حالة المهارة (WP-SSE-SNAPSHOT-BRIDGE) بتاريخ 2026-06-21

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

  • يكتب التشخيصُ المُنهى أدلةَ الفرز لكل مهارة فرعية، ويُشغّل محرّك حالة المهارة، ويكتب البلاطات الكبرى الست مع صفّ GLOBAL العام. تُرجع أسطحُ التقارير وملف المدرسة وتعدّد المدارس وولي الأمر بلاطاتِ الطالب الحقيقية.
  • كل لقطة مُلحقة فقط، وغير قابلة للتكرار عبر مفتاح مثبَّت بالإصدار، ومُجمَّدة على وقت إنهاء الجلسة لإعادة تشغيل حتمية. وإعادةُ الإنهاء لا تكتب شيئًا جديدًا.
  • كل لقطات الحالة الكبرى وحالة المهارة وحالة المجال تُفهرَس على معرّف ملف الطالب. وتمّت مواءمةُ قُرّاء التقارير وملف المدرسة وتعدّد المدارس وولي الأمر والملف على ذلك المعرّف.
  • يُبقي جدولُ اللقطات الكبرى على أسماء أعمدته المُطبَّقة. والتغيير الوحيد في المخطّط هو مفتاح تفرُّد مثبَّت بالإصدار لكل نافذة.

لوحة مدير المدرسة (WP-PRN-FE) — 2026-06-21

واجهة أمامية فقط — دون أي تغيير في الخادم أو المواصفة. صار لشخصية «مدير المدرسة» لوحةُ صحّةٍ مدرسيّةٍ على المسار /principal، ضمن واجهة الكبار. تُركَّب من واجهات تجميعٍ مشحونةٍ سابقاً؛ ولمّا لم تُشحَن واجهة تجميعٍ موحَّدة بعد، تَربط الواجهة الأماميةُ قراءتين مباشرةً.

  • اكتشاف المدارس عبر GET /api/schools، التي تَحصُر مدير المدرسة بمدرسته وحدها (TENANCY-C2). مدرسةٌ واحدة ← الهبوط مباشرةً على اللوحة؛ عدّةُ مدارس (بمستوى المشرف) ← مُنتقي المدارس على /principal/schools.
  • بيانات حيّة من GET /api/schools/{schoolId}/overview (WP-10-BE) — أعدادُ المجالات الحقيقية لكلّ صفّ، وتوزُّع المجالات على مستوى المدرسة، وإجمالي الطلاب، وحداثة اللقطة. ومخطَّط البيانات تجميعيٌّ فقط (الصفّ هو أدقّ مستوى، ومعلومات الطالب محجوبة على مستوى المخطَّط)؛ فلا تَصِل أيّ صفوفٍ على مستوى الطالب إلى الصفحة.
  • مقاييس المنهاج تَعرض مسمّيات المنهاج العربية الحقيقية من GET /api/principal/schools/{id}/overview (WP-STD-BE). في الموجة الأولى لم يُربَط التجميع لكلّ مقياسٍ بعد، فتَصِل الأعدادُ صفريّةً ويَعرض كلُّ مقياسٍ حالةَ انتظارٍ هادئةً «بانتظار تراكم البيانات» — مكتملٌ بنيويًّا، دون أيّ أرقامٍ مُختلَقة.
  • لا نسبةَ مئويّةً عامّةً واحدة (V-3) — كلُّ سطحٍ هو كلمةُ حالةٍ مع عدٍّ صحيح. أمّا الخريطة الحرارية ومؤشّر صحّة القراءة في المدرسة ومقياس كفاية البيانات فمُعلَّمةٌ «قريبًا» بانتظار تمريرة التجميع في WP-PRN-BE. ولا يَظهر تقرير الوزارة.

لوحة المشرف متعدّد المدارس (WP-MSA-FE) — 2026-06-21

واجهة أمامية فقط — دون أي تغيير في الخادم أو المواصفة. صار لشخصية المشرف متعدّد المدارس لوحةٌ على مستوى المؤسسة ضمن واجهة الكبار، تستهلك مسارات المؤسسة المشحونة في WP-MSA-BE.

  • ثلاثة عروض تحت /manager/orgs/[orgId]: نظرة عامة (بطاقات تجميعية لكل مدرسة + إجماليّات المؤسسة)، والمقارنة (مصفوفة حالات: المجال × المدرسة بالأعداد)، والتغيّر عبر الزمن (رسم بياني لعدد الطلاب بحاجة إلى متابعة لكل مدرسة عبر فترات القياس). ويُحوِّل /manager إلى مؤسسة المستخدم.
  • بيانات تجميعية فقط — تظهر أسماء المدارس والأعداد فقط؛ ولا يظهر أيّ اسم طالب أو معلّم أو صفّ فرديّ على أيّ سطح (تُسقِط واجهات الخادم بيانات الطلاب على مستوى المخطّط).
  • عرضٌ محايد — المقارنة جنبًا إلى جنب بالأعداد مع ترتيب المدارس أبجديًّا، دون أيّ ترتيب تفضيليّ أو لوحة صدارة ودون درجة مركّبة.
  • أعدادٌ فقط (لا نِسَب مئوية، V-3)؛ وتُعاد كلمات الحالة من خرائط العرض المشحونة؛ وصفرٌ من مصطلحات الأطر الدولية (Q15). والرسم البياني SVG داخليّ قائم بذاته (دون أيّ اعتمادية جديدة)؛ وألوان الخطوط تدلّ على هويّة المدرسة لا على شدّة الحالة.

لوحة إدارة معايير القياس (WP-STD-ADMIN) — 2026-06-20

لا مسارات جديدة — أُضيفت مُرشِّحات اختيارية إلى قراءتين قائمتين لمدير النظام؛ والتبديل مُعاد استخدامه كما هو. لوحة خلفية لمدير النظام/الشريك من أجل استعراض معايير القياس وتفعيلها ومراجعة سجلّها، ضمن واجهة الكبار.

  • صار GET /api/admin/benchmark-profiles يقبل مُرشِّحات اختيارية: country وskillId وassessmentType وgradeBand وisActive (تُدمَج بـ«و»؛ والاستعلام الفارغ يُعيد كلّ الصفوف كالسابق).
  • صار GET /api/admin/benchmark-profile-changelog يقبل benchmarkProfileId اختياريًا لقراءة سجلّ مراجعة معيار واحد (وعند غيابه يُعيد السجلّ الكامل كالسابق).
  • يُعيد التبديل استخدام مسار الكتابة المُقفَل القائم — دون إضافة كاتب ثانٍ، فيبقى فحص مسار الكتابة الواحد أخضر.
  • تبقى كلّ المسارات محصورة بمدير النظام الأعلى. تعرض اللوحة مسمّيات المنهاج العربية فقط؛ ولا تظهر أيّ مقاييس داخلية في الواجهة (Q15).

واجهة الإحماء الذهني للطالب (WP-WARM-FE) — 2026-06-20

واجهة أمامية فقط — دون أي تغيير في الخادم أو المواصفة. صار للإحماء الذهني غير اللغوي (٣–٥ دقائق) شاشةُ طالبٍ على المسار /student/warmup، مبنيّةٌ على هيكل «عالم الطالب». وهي تستهلك واجهة warmup المشحونة سابقاً في WP-WARM-BE.

  • عارضٌ مُوجَّهٌ بالبيانات. سجلٌّ واحد يختار العارض المناسب من بيانات التمرين (select / positions / buckets / go_nogo) — دون شاشةٍ منفصلةٍ لكلّ نوع تمرين.
  • هادئٌ بالتصميم. أشكالٌ بلا كلمات، دون عدّاد تنازليّ، ومسارُ «تخطٍّ إلى المهمة» بلا عقوبة، وبلا درجةٍ أو ترتيب. ولا يغذّي الإحماء محرّك القياس إطلاقاً.
  • يستأنف عند الانقطاع. التحديث أو القفل أو تبديل التطبيق يُعيد الطفل إلى خطوة التمرين نفسها من ذاكرة المتصفّح.

ملخّص الصفّ للمعلّم + إعادة القياس (WP-07-FE / WP-08-FE) — 2026-06-20

لا مسارات جديدة في الخادم — كلاهما واجهتان أماميّتان تستهلكان واجهات مشحونة مسبقًا (قراءات التقارير WP-06-BE + إعادة القياس WP-08-BE).

  • ملخّص الصفّ (/teacher/class/[classId]/summary) — المكمّل التقريري للوحة الصفّ التشغيليّة. يعرض توزيع مستويات الدعم، وشبكة المجالات السداسيّة المعاد استخدامها، وجدول توزيع حالات المهارات (أعداد بحاجة لتدخّل لكلّ مهارة)، وقائمة المقترَحين لإعادة القياس. كلّ رقم هو كلمة حالة × عدد — لا نسبة مئويّة عامّة واحدة أبدًا (V-3).
  • إعادة القياس — يفتح زرّ المعلّم في ملفّ الطالب جلسة إعادة قياس (POST /api/diagnostic-sessions/start/re-diagnostic؛ مهلة الأربعة عشر يومًا مفروضة في الخادم)، وتعرض صفحة المقارنة (GET /api/reports/students/{id}/re-diagnostic-comparison/{sessionId}) حالة كلّ مهارة فرعيّة قبل ← بعد مع اتجاه النموّ. لغة نموّ فقط — لا تصل أيّ درجة قدرة خام إلى أيّ طرف؛ والتراجع يُؤطَّر للمراجعة لا للإخفاق (V-12).

معايرة راش الحقيقية (WP-CAL) — 2026-06-20

لا مسارات جديدة. صار تقدير قدرة المتعلّم (θ) في محرّك التشخيص يُنتَج عبر مُقدِّر راش 1PL حتميّ حقيقي (EAP) بدل النموذج المغلق الصوري. والقيمة rasch_1pl_v1 في EngineImplementation هي الافتراضية؛ ويبقى النموذج الصوري قابلاً للاختيار لإعادة تشغيل الجلسات الأقدم.

  • صعوبة بمسارين. يستخدم السؤال صعوبته المقيسة بمجرّد بلوغه 300 استجابة حقيقية أو أكثر، ويستخدم التقدير الحتميّ (delta_prior) قبل ذلك. وتُثبّت الجلسات إصدار معايرة مُجمّداً، فلا تتزحزح صعوبةٌ في منتصف الجلسة (V-6).
  • خطّ معايرة غير متصل (services/calibration/، بايثون + girth) يُلائم صعوبات 1PL لكلّ مهارة فرعية ويسكّ لقطة مُرقّمة جديدة في كلّ تشغيل؛ وقد جرى التحقّق من استعادته صعوبات معلومة على بيانات تركيبية. ولا توجد بعد استجابات تجريبية حقيقية، فهو يُشحَن مبنيّاً وجاهزاً، دون تشغيل فعليّ بعد.
  • دليل جديد: دليل تشغيل المعايرة يغطّي فحص جاهزية البيانات، والتشغيل التجريبي، والتشغيل الحقيقي، وقراءة إحصائيّات الملاءمة، وإعادة ضبط الصعوبة كلّما هبطت استجابات أكثر.

مركز الإشعارات الموحّد (WP-NOTIF-BE) — 2026-06-20

خمسة مسارات جديدة (وسم notifications). صندوق الإشعارات الموحّد عبر جميع الأدوار، يحلّ محلّ أكثر من ستّة أسطح تنبيه متفرّقة كان يواجهها المعلّم في يومه الأول. داخل التطبيق فقط في الموجة الأولى؛ قناة البريد والاشتراك لكلّ نوع تنتقل إلى WP-NOTIF-EMAIL.

  • مقصور على المُستلِم، بلا ثغرة وصول مباشر. المسارات: GET /api/notifications، GET /api/notifications/unread-count، POST /api/notifications/{id}/read، POST /api/notifications/{id}/dismiss، POST /api/notifications/mark-all-read. يستمدّ كلّ مسار هويّة المُستلِم من رمز الدخول (لا يوجد مُعامل userId في المسار). يقرأ المستخدم ويُعدّل صفوفه فقط؛ ومعرّف لا يملكه يُعيد 404 لا 403، فلا يُكشف وجود معرّف في صندوق آخر.
  • عزل المستأجر والأدوار. يُخزَّن organizationId على كلّ صفّ؛ فلا يقرأ معلّم إشعارات مدرسة أخرى ولا إشعارات وليّ أمر.
  • بوّابة notifications.dispatch() الداخلية (بلا واجهة HTTP) هي مسار الكتابة الوحيد: تحقّق Zod لكلّ نوع (Q18 بلا نصّ حرّ)، ثمّ تكوين القالب العربي، ثمّ مرشّح سلامة اللغة على العنوان والنصّ المُكوَّنين (حجب صارم بلا نصّ بديل)، ثمّ تحديد المؤسسة والدور، ثمّ الإدراج. بلا نماذج لغوية كبيرة (V-5).
  • تسعة أنواع في الموجة الأولى. الصفوف غير قابلة للتعديل بعد الإنشاء (يتغيّر حقل حالة التسليم فقط)؛ والإشعار المُستبعَد لا يظهر مجدّدًا في أيّ قائمة.
  • تتبنّى الوحدات المُنتِجة البوّابة ضمن تغييرها الخاص؛ هذا الإصدار يقدّم البوّابة والاختبارات. عدد العمليات أصبح 202.

خادم واعٍ بالجهاز (WP-CLIENT-CTX-BE) — 2026-06-20

لا مسارات جديدة — وسيط واحد + مُحدِّد طبقة أصول نقيّ + حقل قياس + فحص العزل (83-client-and-device-support المتطلّبان FR-CLIENT-8/9، القاعدة الصارمة B.27).

  • عقد ترويسة X-Client. ترسل الواجهة ترويسة قدرات واحدة مُتحقَّقة بـ zod — X-Client: {"class":"phone|tablet|desktop|projector","standalone":bool,"bandwidth":"slow|normal|fast|unknown","reducedData":bool,"viewport":"xs..xl","appVersion":"…"}. يحوّلها وسيط client-context إلى c.var.client. قدرات فقط، بلا أي بيانات تعريف شخصية (تُرفض المفاتيح الزائدة/المجهولة). آمن عند الفشل — الترويسة الغائبة أو المشوَّهة ترجع إلى قيم افتراضية آمنة (desktop / unknown)، ولا تُنتج خطأً أبداً.
  • القياس. تحمل سجلّات الطلبات الآن حقل صنف الجهاز client (اختياري، إضافي، متوافق مع السابق).
  • طبقات أصول متكيّفة (FR-CLIENT-9). يُرفق تقديم المهمة الحقل presentation.assetTier ({ audio: lo|hi, image: 1x|2x }) المختار من قدرات العميل — والطبقة الخفيفة هي الافتراض. يغيّر هذا حجم البايتات المُقدَّمة، لا العنصر نفسه: العنصر نفسه وخياراته وإجابته الصحيحة وصفّ التدقيق متطابقة مهما كان الجهاز.
  • حارس الحتمية (B.27 / V-6). فحص CI، lint:client-context-isolation، يُفشِل البناء إذا قُرئ سياق الجهاز/العميل داخل أي مسار قياس أو قرار أو تخويل. ويُثبت اختبارُ حتمية عبر الأجهزة أن المدخل ذاته على صنفَي جهاز يُنتج قياساً متطابقاً بايتاً ببايت.
  • 🚩 بانتظار الشريك (25 يونيو): عناوين الأصول الحقيقية لكل طبقة وعتبات معدّل البِت/الدقّة الدقيقة تأتي مع خطّ إنتاج الصوت/الرسوم (OQ-CLIENT-2)؛ تُعلَّم الطبقة المختارة الآن لتستهلكها الواجهة/شبكة التوزيع.

إعادة القياس التشخيصي (WP-08-BE) — 2026-06-20

مسارَان جديدان (وسم re-diagnostic). تستطيع المنصة الآن فتح تشخيص إعادة قياس مركّز بعد دورة تدخّل، ومقارنة النتائج بالجلسة التشخيصية السابقة.

  • بوّابة 14 يوماً. POST /api/diagnostic-sessions/start/re-diagnostic يفتح جلسة إعادة قياس. يُرجع 409 إذا كان التشخيص المكتمل السابق أقل من 14 يوماً.
  • أرشفة قائمة الانتظار. يؤدّي فتح إعادة التشخيص إلى أرشفة قائمة التدريب النشطة للطالب، حتى يبدأ من جديد بعد إعادة القياس بدل الاستمرار في المنتصف.
  • مقارنة جنباً إلى جنب. GET /api/reports/students/:id/re-diagnostic-comparison/:sessionId يقرن إعادة التشخيص بأحدث جلسة تشخيصية مكتملة سابقة، ويُرجع لكل مهارة فرعية { priorStatus, currentStatus, statusTransition, growth }. قيمة growth واحدة من improved، أو declined، أو same، أو indeterminate. لا يغادر θ الخام الخادمَ أبداً (FR-RPT-3/9 no-leak).
  • التخويل: المعلّمة (ClassTeacher للصف الخاص) أو المسؤول أو RUN_BACKOFFICE؛ الطلب خارج المؤسسة يُرجع 404.

بنية الأجهزة والعملاء — تطبيق ويب تقدّمي + طبقة القدرات (WP-CLIENT-INFRA-FE) — 2026-06-20

النصف الأمامي من عقد دعم الأجهزة والعملاء (القاعدة الصارمة B.27 · المواصفة 83-client-and-device-support). يُحَلّ مرة واحدة على مستوى المنصّة لترث كل الشاشات — الحالية والمستقبلية — السلوك المتجاوب والعمل دون اتصال عبر فئات أجهزة المدارس الأربع (الهاتف، اللوحي/آيباد، الحاسوب المكتبي/المحمول، عارض الصفّ).

  • طبقة قدرات واحدة، لا اعتماد على سلسلة المتصفّح. مزوّد واحد يحدّد فئة الجهاز من حجم الشاشة وقدراتها (نوع المؤشّر، توفير البيانات، وضع التطبيق المثبّت، سرعة الشبكة) ويتيحها عبر useClient(). التخطيط يبقى مدفوعًا بنقاط الكسر في CSS؛ ولا تُقرأ سلسلة المتصفّح (User-Agent) لاتخاذ قرار تخطيط أبدًا.
  • نقاط كسر معيارية مُعرّفة مرة واحدة (sm 480 / md 600 / lg 1024 / xl 1280)، فتصبح مصفوفة الأجهزة المرجع الوحيد للعروض. يطوي هيكل البالغين الشريط الجانبي إلى شريط سفلي دون md؛ وعالم الطالب يملأ الشاشة؛ وعارض الصفّ لا يُظهر أي تفاصيل خاصّة بطالب بعينه (عدم التسريب).
  • تطبيق ويب قابل للتثبيت. بيان تطبيق (“أمل”، أيقونات قابلة للقَنْع، اتجاه من اليمين، سمة فاتحة) مع عامل خدمة يخزّن هيكل التطبيق مسبقًا ويقدّمه دون اتصال، مع إشعار غير صامت بوجود تحديث (لا إعادة تحميل مفاجئة). لا يخزّن العامل سوى الأصول الثابتة، ولا يمسّ ذاكرة جلسة الطالب الجارية.
  • إجابات الطالب لا تضيع دون اتصال. يواصل الطالب الذي انقطع اتصاله أثناء التدريب الإجابة؛ تُحفظ الإجابات محليًّا وتُرسَل عند عودة الشبكة بمفتاح عدم التكرار، فيسجّلها الخادم مرة واحدة (دون ازدواج). أمّا قرارات المعلّم وأي كتابة قياس فتبقى متّصلة فقط مع حالة هادئة “لا يوجد اتصال” — دون نجاح زائف. الخادم هو المرجع دائمًا.
  • ترويسة X-Client وميزانيات الأداء. يحمل كل طلب واصفًا للقدرات فقط (دون بيانات تعريف شخصية) لأغراض القياس والأصول المتكيّفة مستقبلًا؛ ولا يؤثّر في أي قياس (الحتمية، V-6). يفرض Lighthouse-CI سقفًا لحجم جافاسكربت وزمن التفاعل على ملف تعريف منخفض الموارد (جهاز المدرسة هو المعيار). وتعمل مصفوفة أجهزة من أربع عروض في كل حزمة عمل أمامية.
  • 🚩 بانتظار الشريك (25 يونيو): الحدّ الأدنى لمواصفات أجهزة المدارس (يحدّد أرضية الأداء الحقيقية وقيود تطبيق الويب على متصفّح iOS) وعتبات مستويات الأصول.

محرّك تجميع الجلسة (WP-ISM) — 2026-06-20

ثلاثة مسارات جديدة (وسم ism). نموذج السقالات المتكامل (“المايسترو”) — المنسّق الذي يبني جلسة تدريب متماسكة الموضوع من بنك العناصر التشغيلي المتوفّر: موضوع واحد، وسلّم وحدة نموّ الجملة، ومهارات متشابكة على عائلة كلمات واحدة، فلا ينتقل الطفل بين تدريبات غير مترابطة.

  • يختار ولا يولّد. يختار ISM عناصر بنك كاملة ومعايَرة ومعتمَدة من خبير المحتوى فقط — لا توليد وقت التشغيل ولا نموذج لغوي (V-5). التشخيص لا يستدعيه أبداً (V-3)؛ يبقى اختباراً تكيّفياً صرفاً.
  • حتمي (V-6). الطالب + الموضوع + البذرة + لقطة بنك العناصر نفسها ⇐ جلسة متطابقة بايتاً ببايت ومعرّف تشغيل نفسه. أي تغيّر في البنك يُنشئ تشغيلاً جديداً؛ لا يُعدَّل التاريخ أبداً.
  • وضعان، نقطة وصول واحدة. تدريب عام (قائمة مهارات فرعية) أو سياق حزمة (مرساة + داعمتان كحدّ أقصى + جسر أصول، موزونة بنموذج المسار المتشابك مع كون حصّة المرساة دائماً الأكبر).
  • آمن عند الفشل. سلّم تخفيف من أربع خطوات (توسيع النطاق ← الحقل الدلالي ← إسقاط تسلسل النموّ ← فشل ليّن) يَسِم الجلسة القصيرة بأنها ناقصة بدل حشوها. كل جلسة رابعة تُفسح المجال لفحص CBM.
  • لا يُحجب الوصول إلى التدريب أبداً. تُقيَّد جلسات RTI القائمة على الحزمة فقط (409) عند عدم كفاية الأدلة أو التراجع الحاد؛ ويرى المعلّم/الوليّ نصّ لغة نموّ، لا رمز الخطأ.
  • جدولان جديدان: assembly_run (تدقيق/إعادة اشتقاق إضافة فقط) + assembly_rule_set (إعداد مُصدَّر). مزيج FSRS ومعالجة اللهجة وإدراج الفحص مُعلَّمة بانتظار قرار الشريك (25 يونيو).

وضع الدرس التزامني (WP-18-BE) — 2026-06-20

سبعة عشر مساراً جديداً (وسم sync). الواجهة الخلفية لدروس المعلّم التزامنية، حيث يعرض المعلّم جلسة حية ويُجيب الطلاب على أجهزتهم عبر الاستقصاء الدوري REST بلا WebSocket أو SSE (قيد Q-SYNC-1 LOCK لأجهزة المدارس التجريبية ذات الموارد المحدودة).

  • دورة حياة الجلسة. POST /api/sync/sessions تنشئ مسودة جلسة برمز انضمام رقمي؛ POST …/start تُفعّلها؛ GET …/summary تُرجع النتائج المجمّعة أو لكل طالب بعد انتهاء الجلسة.
  • ثلاثة أوضاع. الفصل الكامل، والاستجابة الجماعية، وعارض الشاشة الشخصي. في وضع العارض الشخصي يُرسَل عنصر مختلف لجهاز كل طالب بينما تبقى شريحة مشتركة على الشاشة المعروضة. المسارات: …/personalized-projector/setup, …/answer-key, …/mark, …/commit.
  • المجموعات بقيادة المحدَّد. POST …/groups ينشئ مجموعات الطلاب بقائد محدَّد؛ PATCH …/groups/:groupId/leader ينقل القيادة.
  • الاستقصاء الدوري REST. يستقصي الطلاب والمعلّمة GET …/poll وGET …/events للتغييرات في الحالة. تُرسَل الإجابات إلى POST …/responses؛ POST …/observation يسجّل ملاحظة المعلّمة.
  • القائمة والتحكّم. POST …/playlist يحمّل تسلسل العناصر؛ POST …/control يتحكّم في التشغيل، والإيقاف المؤقت، والانتقال، والإنهاء. تستطيع الجلسات الارتباط بتشغيل ISM عبر POST …/ism-run.

خادم التحفيز (WP-14-BE) — 2026-06-20

سبعة مسارات جديدة (وسما gamification + leaderboard). محرك التحفيز المرتبط بالتعلّم: سجلّ أحداث الإتقان (ثمانية أنواع مصدر مغلقة)، ونقاط الخبرة المشتقّة، والأوسمة، وصورة رمزية تجميلية، وسلاسل لطيفة، ولوحات صدارة المعلّم والمدير، ومسار إلغاء الوسام، وتدقيق المسؤول وإعادة الاشتقاق.

  • كل مكافأة تعود إلى حدث إتقان مقاس (V-8). لا تُمنح النقاط/الأوسمة إلا من أحد أنواع المصدر الثمانية — عدد الجلسات، والوقت على التطبيق، وسلاسل تسجيل الدخول لا تمنح شيئاً أبداً. يتحقّق فحص آلي من أن كل قاعدة منح وسام تستند إلى مصدر مقاس.
  • لا لوحة صدارة للطالب أبداً. لوحات الصدارة للمعلّم (عدّة صفوف) وللمدير (المدرسة) فقط؛ رمز الطالب يُرفض (403) على كل مسار صدارة. صفحة نقاط الطالب تعرض بياناته وحده — لا مقارنة بالأقران ولا ترتيب.
  • عديم التكرار وقابل لإعادة الاشتقاق. الإصدار عديم التكرار على المفتاح الطبيعي؛ رصيد النقاط مشتقّ من السجلّ المُلحَق فقط (لا يُخزَّن)؛ إعادة اشتقاق المسؤول تعيد حساب الرصيد/الأوسمة/الصورة وتقارن بصفر انحراف.
  • الإلغاء = رمز مضبوط واحد، بلا نص حرّ. يُلغي المعلّم عبر الرمز التاسع الوحيد Gam_Award_Invalid_05؛ تُلحَق حركة تعويض معاكسة؛ ويُحفَظ صفّ المنح الأصلي.
  • القيم الافتراضية العاملة (قيم النقاط، وسقف 200/جلسة، وعتبات الصورة/السلسلة، وكتالوج الأوسمة الخمسة عشر بالعربية) مزروعة ومُصدَّرة ومُعلَّمة بانتظار الشريك لجلسة 25 حزيران — لم يُختلق شيء.

أدلة حلقة القرار — الأمانة وحزم القرار وغرفة البيانات — 2026-06-20

لا تغيير في الواجهة. ثلاثة أدلة مطوّرين جديدة تحت الأدلة، مبنية على شيفرة الوحدات المشحونة، تمنح موجة قرارات الاستجابة للتدخل تغطيتها على مستوى الواجهة: متتبّع أمانة تنفيذ التدخل (بوابة التصعيد: النسبة والتصنيف والحكم وescalationBlocked)، وحزم القرار (سير عمل التجميع ثم الاعتماد أو الرفض الذي يستدعي محرك RTI لنقل المستوى)، وغرفة بيانات الطالب (الملفّ + فهرس الأدلة + هيكل الحزمة). يوثّق كلٌّ مساراته الحقيقية وصلاحياته وأشكال حقوله، مع ثوابت الفشل المغلق والإلحاق فقط وتثبيت الإصدار والسبب المضبوط وعدم الظهور للطالب أبداً. تطابق إنجليزي + عربي.

دليل المنصة — بوّابة التوثيق الخارجي — 2026-06-20

لا تغيير في الواجهة. نكهة توثيق ثانية لجمهور غير تقني، تُقدَّم تحت بادئة المسار /external. يحمل الشريط العلوي تبويبَين، وثائق المطوّرين ودليل المنصة، وتعرض كل بوّابة قائمتها وحدها (تتبدّل القائمة الجانبية حسب البوّابة). ولم تتغيّر مسارات وثائق المطوّرين.

  • 27 صفحة معمّقة بالإنجليزية والعربية، مبنية على شيفرة الوحدات الفعلية، منظّمة في ستة أقسام: القياس والقرارات، والتدخل والتدريس، والمراقبة والاستجابة، والتقارير ولوحات المعلومات، وأسس المنصة، إضافةً إلى نظرة عامة، والثقة والخصوصية، وخارطة الطريق، والأسئلة الشائعة. تشرح كل صفحة قدرةً حقيقية من طرفها إلى طرفها بقواعدها وعتباتها الحقيقية، بلغة منتج واضحة (بلا نقاط نهاية أو مخطّطات أو معرّفات داخلية).
  • مكتوبة بلغة النموّ فقط: لا تسميات سريرية أو برامجية، ولا نتيجة إجمالية واحدة، وفصلٌ صادق بين المتاح الآن والمخطّط له.
  • يتشارك البوّابتان التطبيق والسمة والبحث؛ ويثبت تطابق الإنجليزية/العربية (60/60).

البوّابة — أدلة شاملة للمرحلة الأولى — 2026-06-20

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

  • قسم مفاهيمي جديد “كيف تعمل المرحلة الأولى” — حلقة الاستجابة للتدخل، القياس والحتمية، محرك القرار، تصميم التدخل، وقواعد السلامة.
  • 16 دليلًا جديدًا للأنظمة الفرعية تحت الأدلة — التشخيص والتدريب، وتصنيف المهارات، ومحرك حالة المهارة، وملفات الطلاب، وحزم التدخل، والتجميع الذكي، وتفعيل المعلم، ومراقبة التقدم، والقياس المنهجي وطلاقة القراءة، وقرارات الاستجابة للتدخل (معاينة)، والمعايير والمحكات، وتسليم المهام، والتقارير وملف ولي الأمر، والإحماء الذهني، وسلامة اللغة، وفحوصات جودة النظام.
  • مصطلحات جديدة وثلاثة إصلاحات لصفحات قديمة (نظرة عامة، نتائج «التوقّف الآمن» في الأخطاء، وتجميع المنسقين والمدراء الذي صار مأهولًا).
  • كل صفحة تُشحن بـ الإنجليزية + العربية (تطابق 33/33)؛ وكل الروابط الداخلية صالحة.

بوّابة وليّ الأمر — 2026-06-20

أربع عمليات قراءة جديدة تحت وسم parent-portal جديد (يصبح العدد 171) — عرضُ وليّ أمرٍ موثَّق لأبنائه.

  • GET /api/parent/children (الأبناء المرتبطون)، …/:childId/diagnostics (سجلّ بالحالة فقط)، …/:childId/growth (مسار حالة المجالات، تسميات عربية فقط)، …/:childId/recommendations (≤5 اقتراحات منزلية من سرد D2 المولّد مسبقًا — لا نموذج لغوي وقت التشغيل).
  • الأبناء المرتبطون فقط. وليّ الأمر هو المستخدم الموثَّق (لا :parentId في أيّ مسار ← لا IDOR)؛ ويُفحَص كل :childId مقابل رابط ParentStudent — ابنٌ غير مرتبط داخل المؤسسة ← 403، وابنٌ عبر المؤسسات/غير موجود ← 404. ويرى وليّ الأمر متعدّد الأبناء جميع أبنائه المرتبطين.
  • آمن من التسريب بالتصميم (حِزامان). DTO بقائمة سماح مكتوبة + مرشّح الصرامة-لوليّ-الأمر النصّي — لا θ ولا أرقام ولا نِسَب ولا تسميات داخلية تصل إلى وليّ الأمر (طفلٌ ببيانات θ/ملفّ/نسبة حقيقية لا يُظهَر منها شيء). يفشل مغلقًا (503) إن غابت قواعد المرشّح.
  • لا ملخّص واتساب، لا تخزين هاتف (D1) — كل المسارات GET للقراءة فقط؛ لا تخزّن البوّابة شيئًا عن وليّ الأمر.

نظرة إدارية متعدّدة المدارس — 2026-06-20

ثلاث عمليات جديدة تحت وسم multi-school جديد (يصبح العدد 167) — تجميعٌ على مستوى المؤسسة لمدير الشبكة، مبنيٌّ فوق عرض المدرسة الواحدة.

  • GET /api/orgs/:orgId/overview — بطاقة تجميع لكلّ مدرسة (الاسم + إجمالي الطلاب + عدد الصفوف + كم منهم يحتاج دعمًا). GET /api/orgs/:orgId/comparisons — مجالات القراءة الستّة × N مدرسة جنبًا إلى جنب، كأعداد حالة. GET /api/orgs/:orgId/trends — سلسلة زمنية للمؤسسة، خطٌّ لكلّ مدرسة × مجال، عبر نوافذ شهرية.
  • المقارنة تجميع حالة محايد، وليست ترتيبًا — لا ترتيب أفضل/أسوأ، ولا لوحة صدارة للمدارس. ويظهر المجال الجامع كبطاقة “قريبًا”.
  • تجميعيٌّ بالتصميم. يُظهر أسماء الصفوف لكنه لا يُظهر أبدًا اسم طالب أو معرّفه في أيٍّ من الاستجابات الثلاث — نفس حارس الـ lint (مُوسَّعًا على هذا الوحدة) + اختبارات تزرع اسمًا مميَّزًا وتؤكّد غيابه. لا θ، ولا نسبة عامّة واحدة (V-3)؛ ويُستثنى Not_Assessed من أيّ تجميع.
  • يرى المدير كلّ مدارس مؤسسته افتراضيًّا (لا واجهة تحديد جزئي في الموجة الأولى)؛ ويُعيد المعرّفُ خارجَ المؤسسة 404. للمدير/المشرف فقط — لا للمعلّم ولا للطالب.
  • يعيد استخدام محرّك تجميع المدرسة وقُرّائه المُسلَّمين (لا جداول جديدة، لا منطق قياس). قراءاتٌ مُجمَّعة تفي بميزانية ≤5 ثوانٍ لمؤسسة من 10 مدارس.

تغطية سرد وليّ الأمر (مولّد بالذكاء الاصطناعي، مبدئي) — 2026-06-20

عملية إدارية واحدة جديدة (يصبح العدد 164) + تغيير محتوى وبيانات بحيث يُظهر تقرير وليّ الأمر وبوّابته شرحًا مكتوبًا للنموّ لـ كلّ ملفّ، لا للملفّين المكتوبين من الشريك فقط.

  • 56 سردًا عربيًّا لوليّ الأمر (12 أساسيًّا + 5 معدِّلة × نطاقات الصفوف) مولّدة من مواصفات الملفّات ومزروعة كطبقة مبدئية. كلٌّ موسوم ai_generated + needs_sme_review ويجتاز مرشّح الصرامة-لوليّ-الأمر دون تغيير — لا أرقام، لا θ، لا تسميات داخلية، لغة نموّ فقط (نفس انضباط V-12/V-3).
  • تُعرض حيّة، موسومة (قرار محمد): يرى وليّ الأمر الشرح الآن؛ ويراجعها الشريك ويستبدلها في جلسة 25 يونيو. يُستبدَل عرض وليّ الأمر فقط — تبقى سرود المعلّم والمشرف والطالب من تأليف الشريك. وتبقى صفحة “نحتاج بيانات إضافية” الآمنة لحالات غياب الملفّ الحقيقية، لا لـ”لم يُكتب السرد بعد”.
  • GET /api/admin/profile-narratives/pending-review يسرد الصفوف المبدئية لطابور مراجعة الخبير (RUN_BACKOFFICE فقط).

نظرة عامة على المدرسة + تقرير المجلس (PDF) — 2026-06-20

عمليتان جديدتان تحت وسم board-pdf جديد (يصبح العدد 163) — عرضٌ على مستوى المدرسة للمديرين ومديري الشبكات.

  • نظرة عامة (JSON) + تقرير مجلس بصفحة واحدة A4 عربي RTL لاجتماع مجلس/إدارة: أعداد حالة المجالات لكل صفّ + التوزيع على مستوى المدرسة عبر مجالات القراءة الستّة (+ بطاقة “قريبًا” للمجال الجامع).
  • تجميعيٌّ بالتصميم. يُظهر أسماء الصفوف (ليتصرّف المدير) لكن لا يُظهر أبدًا اسم طالب أو معرّفه — يحرس كل مسار قراءة فحصٌ مخصّص، ويزرع اختبارٌ اسمًا معروفًا ويؤكّد غيابه من بايتات التقرير ومن الـ JSON. لا θ، لا نسبة إجمالية واحدة (V-3).
  • يعيد استخدام قارئات التقارير المشحونة + أساس lib/pdf المشترك (خط عربي مضمَّن، حتمية بايتات V-6) الذي صار تقرير وليّ الأمر يُبنى عليه أيضًا — وصفة PDF واحدة، تخطيطان.
  • للمدير/مدير الشبكة/المشرف فقط (المدير يرى مدرسته؛ مدير الشبكة يرى مدارس مؤسسته)؛ غير ظاهر للمعلّم أو الطالب أبدًا. ≤500 كيلوبايت، ≤30 ثانية، يفشل-مغلقًا.

مواءمة مفردات v5 — 2026-06-20

لا تغيير في السلوك. أصبحت طبقة قرارات الاستجابة للتدخّل تُخزّن أسماء رموز الحالة القياسية للشريك (v5) مباشرةً، مع إزالة طبقة ترجمة وسيطة. كفاية البيانات تُقرأ sufficient / insufficient / contextual؛ وقرارات المستوى escalate / de_escalate / maintain / defer؛ وتنبيهات RTI كتالوجها الخماسي Skill_Alert / Student_Alert / Intensive_Review / acute_regression_review / tier_review_due؛ وتُضاف specialist إلى أدوار الاعتماد؛ وحزمة القرار تُقرأ draft / under_review / approved / rejected / deferred. تغيّرت تهجئة الرموز المُخزّنة فقط — أمّا منطق القرار والضمانات والحتميّة (V-6) فلم تُمَسّ، ومخطّطات OpenAPI تعكس أسماء v5.

مسار حزمة القرار — 2026-06-20

أربع عمليات جديدة تحت الوسم الجديد decision-packet (يصبح العدد 161). القطعة الختامية في موجة قرارات الاستجابة للتدخّل: مسار المراجعة والاعتماد الذي يحوّل توصية انتقال المستوى إلى قرار موثّق ومدقّق — وعندئذٍ فقط يُنقَل مستوى الطفل.

  • التجميع. POST /api/decision-packet-workflows/assemble يفتح حزمة قرار غنيّة (الأدلّة مُلتقطة بالإحالة لا بالنسخ، وكلّ إصدار قاعدة/إعداد مُثبَّت لإعادة التشغيل)، ويحسب توصية المستوى الحتميّة، ويسجّل صفّ مسارٍ بانتظار المراجعة.
  • المراجعة والاعتماد. GET /api/decision-packet-workflows/{id} هو واجهة المراجِع؛ وPOST …/{id}/approve يمرّر التوصية عبر بوّابة الاعتماد — وانتقالٌ إلى المستوى الثالث يتطلّب الأخصّائي عالي الكثافة (مُقعَد إداريًّا في الموجة الأولى) — وعند الاعتماد يُنفَّذ انتقال المستوى عبر مسار الكتابة الوحيد للمستوى في محرّك RTI، ثم تُغلَق الحزمة. وPOST …/{id}/reject يسجّل رفضًا بسبب مضبوط؛ دون أي انتقال.
  • لا انتقال دون اعتماد؛ وسبب القرار رمزٌ مضبوط لا نصٌّ حرّ. أي إيقاف «نحتاج مزيدًا من الأدلّة»، أو انتقالٌ غير معتمَد إلى المستوى الثالث، أو ملفّ ناقص — كلّها تحجب الانتقال (فشل آمن). والحزمة المُغلَقة والقرار المُطبَّق غير قابلين للتعديل أبدًا (وإعادة التشغيل تُعيد إنتاجهما).
  • هذا المسار لا يضيف أيّ كتابةٍ للمستوى من تلقاء نفسه — بل يستدعي محرّك RTI لنقل المستوى وغرفة البيانات لفتح/إغلاق الحزمة. مُلحَق فقط، معزول حسب المؤسّسة، مُثبَّت الإصدار (V-6)، ولا يُعرَض للطالب أبدًا.

متتبّع أمانة تنفيذ التدخّل — 2026-06-20

خمس عمليات جديدة تحت الوسم الجديد fidelity (يصبح العدد 152). البوّابة التي تميّز بين «الخطّة لم تنجح» و«الخطّة لم تُنفَّذ»، حتى لا تُصعِّد المنصّة أبدًا حالة طفلٍ لم يُنفَّذ تدخّله فعليًّا.

  • بوّابة التصعيد. GET /api/fidelity/{bundleAssignmentId}/check يُرجع الحكم المتزامن الذي يستدعيه محرّك RTI قبل أي انتقال من المستوى الثاني إلى الثالث: نسبة الالتزام (الجلسات المُنفَّذة ÷ المخطّطة)، تصنيف من خمس قيم، حكم من أربع حالات، وescalationBlocked. التنفيذ الأمين (≥80٪) مع نموٍّ ضعيف قد يُصعِّد؛ ودون 80٪ مع نموٍّ ضعيف يُحظر؛ وغياب بيانات الجلسات يعني «لا يمكن التقييم بعد» — لا تمرير بالتخمين أبدًا.
  • إعادة الحساب + المتتبّع + الفئة. POST …/recompute يُلحق لقطة جديدة غير قابلة للتعديل (مع قفل احترازي، ثابتة الناتج)؛ وGET …/{bundleAssignmentId} يقرأ الأحدث؛ وGET /api/students/{id}/fidelity-tracker يغذّي تبويب الالتزام لدى المعلّمة؛ وGET /api/fidelity/admin/low-fidelity-cohort يسرد الخطط المُعرَّضة (للمدير).
  • فقرة بلغة النمو. كل حكم يُصيغ تلقائيًّا فقرة عربية قصيرة لاجتماع المراجعة — مكتوبة بالقواعد لا بالذكاء الاصطناعي — ومُرشَّحة من اللغة السريرية وأطر القياس الدولية ولغة العجز.
  • غير قابل للتعديل ومثبَّت بالإصدار (V-6)؛ مُقيَّد بالمعلّمة (B.4)؛ معزول بين المؤسّسات؛ لا يُعرض للطالب أبدًا. الحكم المُخزَّن هو ما تقرؤه الآن بوّابة الالتزام في RTI — فلا انتقالٌ تصاعديٌّ بالتخمين يمرّ عن خطّةٍ لم تُنفَّذ.

غرفة بيانات الطالب — 2026-06-20

خمس عمليات جديدة تحت الوسم الجديد data-room. غرفة البيانات هي طبقة توثيق القرار: تجمع أدلّة الطفل في ملفّ قابل للمراجعة بحيث تكون القرارات الكبرى موثَّقة ومستندة إلى الأدلّة وقابلة لإعادة التشغيل بعد سنوات. هي لا تقرّر — القواعد تبقى هي صاحبة القرار؛ وغرفة البيانات تجعل كل قرار حسّاس يُظهر شواهده.

  • ملفّ واحد لكل طفل. GET …/data-room يعيد ملخّصات الأدلّة الثمانية (المعيار، اتجاه القياس CBM، التدريب، الفحوص الورقية، الصيانة، أنماط الخطأ، الالتزام، إشارات السلوك) + حالة كفاية البيانات. الملخّصات تجميعات يولّدها النظام من أدلّة مُشار إليها — لا نصّ حرّ أبدًا، ولا مُدخَل لأي قاعدة.
  • الأدلّة مُفهرسة لا منسوخة. GET …/data-room/evidence يصفّح فهرس الأدلّة؛ كل صفّ يشير إلى سجلّه الأصلي. أدلّة التطبيق غير الصالحة تبقى مُفهرسة (لا يُحذف شيء) لكنها تُستبعَد من حساب الكفاية.
  • هيكل حزمة القرار. POST …/decision-packets يفتح حزمة، ويلتقط الأدلّة بالإشارة، ويثبّت إصدارات القواعد التي قرأها — فتُعاد الحزمة حرفًا بحرف بعد سنوات. فتح ثانٍ لنفس نوع المراجعة يعيد 409؛ والحزمة المغلقة غير قابلة للتعديل إلى الأبد.
  • البيانات الضعيفة تمنع القرار القوي. عندما تكون مهارة في حالة do_not_decide_yet، أو الأدلّة دون العتبة القابلة للمقارنة، يُبلِّغ الملفّ عن insufficient ويوصي بـإجراء البيانات التالي — لا حركة أبدًا.
  • لا حركة مستوى هنا. غرفة البيانات تقرأ سجلّ قرار المستوى وتؤلّفه؛ لكنها لا تكتبه أبدًا. مسار كتابة المستوى الوحيد يبقى في محرّك RTI.
  • لا يرى الطلّاب أيًّا من هذا — لا توجد نقطة وصول للطالب؛ المعلّمة (صفوفها فقط) والمشرف فقط.

محرّك قرارات الاستجابة للتدخّل RTI — 2026-06-20

عشر عمليات جديدة تحت الوسم الجديد rti. هذه هي طبقة القرار المركزية: ترفع التنبيه المناسب على لوحة المعلّمة، وهي البوّابة الوحيدة التي يمرّ منها أي تغيير في مستوى التدخّل RTI.

  • طبقتا تنبيه. الطبقة A هي حالة المهارة الواحدة (on_track / monitoring / maintenance، محسوبة من محرّك حالة المهارة)؛ الطبقة B هي تنبيه الطالب — Skill_Alert (تنبيه مهارة واحدة)، Student_Alert (يحتاج هذا الطالب خطّة دعم موجَّهة)، Intensive_Review (المراجعة الأعمق). يبقى تنبيه واحد مفتوحًا لكل طالب؛ ويُغلق التنبيه الأشدّ تلقائيًا التنبيهَ الأخفّ.
  • قواعد حركة المستوى الأربع. كل تغيير في المستوى يمرّ عبر TM_ESC_01 (تصعيد) / TM_MAINT_01 (إبقاء) / TM_DEC_01 (تخفيض) / TM_BLOCK_01 (حظر عند ضعف الالتزام). المحرّك يقترح؛ المعلّمة توافق؛ والأخصّائي (المُجلَس على مقعد المدير في الموجة الأولى) يضبط بوّابة المستوى الثالث. GET …/recommendation يُرجع الحكم الحتمي؛ وPOST …/decision يُثبّته عبر مسار الكتابة الوحيد المُدقَّق.
  • الالتزام قبل التصعيد. TM_BLOCK_01 يسبق TM_ESC_01: «الخطّة لم تنجح» و«الخطّة لم تُنفَّذ» حكمان مختلفان. وحتى يصل متتبّع الالتزام، يفشل التصعيد بأمان (محظور) — لا تصعيد بالتخمين أبدًا.
  • do_not_decide_yet يحظر كل شيء. عند عدم كفاية البيانات، لا يُفتح تنبيه ولا يتحرّك مستوى — لأي دور، دون تجاوز. ترى المعلّمة رسالة هادئة «نحتاج بيانات أكثر»، لا إنذارًا أحمر.
  • لا ضبط مباشر للمستوى أبدًا. يتغيّر المستوى فقط عبر مسار القرار المُبوَّب الذي يكتب سجلّ قرار غير قابل للتعديل في المعاملة نفسها. تستخدم عمليات الصرف رمز سبب مُتحكَّمًا فيه — لا نصّ حرّ. والطلاب لا يرون أيًّا من هذا.

محرّك متابعة الطلاقة CBM / ORF — 2026-06-20

عشر عمليات جديدة تحت وسمين جديدين — orf + cbm (يصبح العدد 129). تقيس المنصّة الآن طلاقة القراءة وتتابع تحسّنها عبر الزمن.

  • تقييم شفوي بتسجيل المعلّمة، بلا ذكاء اصطناعي. تُسجّل POST /api/orf/assessments/{start, :id/mark, :id/stop} قراءةً شفويّة مدّتها 60 ثانية عبر نقر المعلّمة على الأخطاء (لا تعرّف على الكلام، ولا نموذج لغوي؛ والصوت للأرشفة فقط) ← الكلمات الصحيحة في الدقيقة + الدقّة ← صفّ cbm_scores إلحاقي.
  • خط الهدف وقاعدة النقاط الأربع. تكتب POST /api/cbm/probes عيّنةً؛ ويُفعَّل خط الهدف بعد ثلاث عيّنات أساس (الوسيط)، وتُنتِج آخرُ أربع نقاط متماثلة اتجاهًا مُصنَّفًا (trend_above_goal / trend_below_goal / trend_mixed / insufficient_points). تُعيد GET /api/cbm/trend/... السلسلة + خط الهدف؛ وGET /api/cbm/alerts التنبيهات المفتوحة.
  • إصدار فقط (V-12). يُصدِر المحرّك الإشارة + تنبيهًا خامًا؛ ولا يطبّق بوّابة الالتزام ولا يكتب رسالة المعلّمة (تلك لـ WP-RTI-BE + متتبّع الالتزام، اللذين يقرآن التنبيه خلف بوّابة ≥80%). والتراجع الحاد يرفع الإشارة دون إخفاقٍ تلقائي. ويستخدم الرفض رمز سببٍ مضبوط — لا نصّ حر.
  • النواقص في المعايير صريحة. الصفوف التي لا معيار لها بعد (الأول/الرابع مملوكان للشريك؛ الثاني–الثالث مزروعان) تُسجَّل وتُتابَع على WCPM الخام لكن تُوسَم “غير مُقيَّمة” بدل الحكم عليها بحدٍّ مُختلَق.

محرّك الإحماء الذهني — 2026-06-20

سبع عمليات جديدة تحت الوسم الجديد warmup؛ يصبح العدد 119. هذا هو خادم الإحماء الذهني الذي يستغرق ٣–٥ دقائق قبل جلسة الطالب — إحماء قائم على قواعد، حتميّ، غير لغويّ تمامًا (أشكال وألوان ومسارات — لا كلمات ولا حروف ولا أرقام إطلاقًا).

  • توليد حتميّ ببذرة. عشرة قوالب نشاط من الطبقة الأولى + ٢٤ إعدادًا حسب الصف عبر مولّد مركزيّ واحد؛ النتيجة لنفس (القالب، الصف، الصعوبة، البذرة) تمرين متطابق دائمًا (قابل لإعادة التشغيل V-6 عبر POST /api/admin/warmup/dry-run-replay).
  • قابل للاستئناف ومحدود. POST /api/warmup/sessions ← …/events ← …/complete، مع …/resume الذي يعيد الطفل إلى نفس خطوة التمرين بالضبط. سقف صامت ٥ دقائق؛ التخطّي بلا عقوبة (لا إعادة محاولة ولا أيّ علامة warmup_abandoned).
  • معزول عن القياس — بالتصميم. الإحماء لا يمسّ θ أبدًا، ولا يصدر حدث إتقان، ولا يمنح نقاطًا، ولا يملك أيّ مفتاح خارجيّ إلى أيّ جدول قياس/قرار. حارس رسم بيانيّ للاستيراد + اختبار مفاتيح المخطّط يُثبتان ذلك؛ القياسات إشارة جاهزيّة تُخزَّن في جداول الإحماء وحدها.
  • مُتاح للمعلّم/المشرف ومقيَّد بـ ClassTeacher؛ لا توجد واجهة للطالب (يُسلَّم التمرين إلى العارض).
  • بانتظار الشريك (٢٥ يونيو): إعدادات COG-05 (المطابقة) + COG-06 (التتبّع البصري) حسب الصف تُشحَن مُعطَّلة؛ حدود الصفوف ومكتبة الأصول SVG قيم عمل افتراضية منقولة.

واجهات تشخيص الطالب والتدريب — 2026-06-20

عشر عمليات جديدة تحت وسمين جديدين — diagnostic-session (٦) + practice (٤)؛ يصبح العدد 112. هذا هو جانب الطالب من حلقة الاستجابة للتدخّل: يخضع الطفل لتشخيص ثم يتدرّب تكيّفيًّا.

  • التشخيص (WP-04). POST /api/diagnostic-sessions/start ← تقديم عنصر ← …/responses ← …/finish، حسب الصف (الصف الأول صوت-أولًا، مرتبطًا بصف الطالب نفسه — لا بصف الفصل). حفظ/استئناف لمدة ٢٤ ساعة (رمز حالة موقَّع جذر الثقة فيه هو إعادة تحقّق الملكية من الخادم)، وسقف وقت نشط ١٥ دقيقة (لا تُحتسب التوقّفات وإعادة تشغيل الصوت). يصحّح الخادم كل إجابة ويسلسل θ بنفسه — فلا يستطيع الطالب تزييف الصواب أو توجيه درجته. يجري التقدير عبر المحرّك، وتقديم العناصر عبر خدمة التسليم.
  • التدريب والاختبار التكيّفي (WP-05). تبني POST /api/practice/queues/seed/:diagnosticSessionId طابورًا من التشخيص؛ وتختار …/current/next-item العنصر الأكثر إفادة عند θ±0.5؛ وتُقدّر …/submit-response الإجابة. ضبط الصعوبة لكل كتلة (80/60) مفعَّل، ويعدّل نطاق صعوبة دائمًا لكل (طالب × مهارة فرعية) يُحمَل عبر الجلسات (يستأنف الطالب عند المستوى الذي بلغه). تلميح SOLO عند الخطأ.
  • آمن للطالب بالتصميم. كل ردّ يظهر للطالب يُسلسَل بقائمة سماح — لا تصل θ / تسمية حالة / ملف / حزمة / مستوى سقالة / دقة إلى الطالب أبدًا. محصور بطالبه (لا يمسّ إلا جلسته)؛ والمعلّمة تقرأ ملخّصات جلسات صفّها فقط.
  • ذاكرة المتصفّح واستعادة الاضطرابات الخمسة تغييرٌ أمامي لاحق؛ والخادم يشحن عقد الاستئناف ويختبره. مفردات فئات الأخطاء وأرقام عتبات 80/60 الدقيقة مملوكة للشريك (٢٥ يونيو)، مبنيّة خلف افتراضات عمل موثّقة.

خدمة PDF لولي الأمر — 2026-06-20

عملية واحدة جديدة تحت وسم parent-pdf الجديد (يصبح العدد 113). تستطيع المعلّمة الآن تصدير تقرير نموّ موجّه لولي الأمر كملفّ PDF عربي بحجم A4 ومن اليمين إلى اليسار — تركيب للقراءة فقط، دون أي منطق قياس أو قرار، ودون كتابة، ودون جدول جديد.

  • النقطة. تُعيد POST /api/parent/pdf/:childId ملفّ الـPDF مباشرةً (A4، عربي RTL، خطّ المتن ≥ 12 نقطة، ≤ 500 كيلوبايت، وأقلّ بكثير من حدّ الـ30 ثانية). تُطلَق من المعلّمة أو المشرف؛ ولا تُعرض للطالب أبدًا.
  • أصرم طبقة سلامة في المنصّة. كل نصّ يمرّ عبر مرشّح أولياء الأمور الأكثر صرامة + تجريد حقول مُمَوْضَع: لا يرى وليّ الأمر أي أرقام أو نسب مئوية أو درجات أو رموز داخلية — لغة نموّ فقط (V-3/V-12).
  • الفشل المغلق. الطالب بلا تقرير مُحلَّل ← صفحة “نحتاج بيانات إضافية” صريحة، لا ملفّ مُلفَّق أبدًا. وعند تعذّر مجموعة قواعد السلامة ← 503 بدل إخراج نصّ غير مُرشَّح.
  • عربية تُسافر. الخطّ العربي (Noto Naskh، مضمَّن) يُشحَن داخل الملفّ، فيُعرَض الـPDF بشكل صحيح عند المشاركة (عبر واتساب مثلًا) أيًّا كانت خطوط جهاز المستلِم. محتوى حتمي (V-6)؛ ولا نموذج لغوي (V-5).

واجهات تقرير المهارات الفرعية — 2026-06-20

ثلاث عمليات قراءة فقط تحت وسم reporting الجديد (يصبح العدد 112). هذه طبقة القراءة التي تحوّل أحكام المحرّكات المُخزَّنة إلى تقارير موجّهة للمعلّم والمدير — لا تضيف أيّ منطق قياس أو قرار، ولا تكتب شيئًا.

  • تقرير الطالب. تُعيد GET /api/reports/students/:id/sub-skill-report حمولة واحدة بخمسة أقسام: الملف التعليمي (مع السرد الجاهز للمعلّم)، بلاطات المجالات الكبرى، حالات المهارات الفرعية مرتَّبة “يحتاج تدخّل” أوّلًا، خطة التدخّل النشطة، وأي تنبيهات مفتوحة. الطالب بلا بيانات يُعيد ملفًّا بحالة dataIncomplete (استجابة 200، لا تقرير مُلفَّق أبدًا).
  • ملخّص الصف. تُعطي GET /api/reports/classes/:id/class-summary للمعلّم عدد الطلاب لكل حالة لكل مهارة فرعية + تجميع المجال الكبير للصف (الأسوأ يَغلِب) + صفوفًا لكل طالب في صفوفه هو (عبر وصلة ClassTeacher). مع ?audience=manager تتحوّل إلى عرض تجميعي فقط بلا أسماء أو معرّفات طلاب.
  • مرجع النطاقات. تُعيد GET /api/reports/band-descriptions كتالوج “ميزان” بخمسة نطاقات، مُخزَّن 24 ساعة (التسميات قيم افتراضية بانتظار اعتماد الشريك).
  • السلامة. لا نسبة مئوية إجمالية (V-3)؛ كل نصّ يمرّ عبر مُرشِّح سلامة اللغة (V-12)؛ كل استعلام محصور بالمؤسسة (عبر المؤسسات ← 404)؛ لا نموذج لغوي (V-5). للمعلّم (عبر ClassTeacher) والمدير فقط.

محرّك التشخيص (تقدير القدرة θ) — 2026-06-20

أربع عمليات جديدة تحت وسم engine الجديد (يصبح العدد 96). هذا هو قلب القياس: يحوّل إجابات الطالب التشخيصية إلى تقدير للقدرة (θ) ويختار السؤال الأنسب التالي.

  • التقدير. تأخذ POST /api/engine/score إجابات الطالب + θ سابقة وتُعيد {newTheta, newSE, calibrationVersion, nextItemId, calibrationProvisional}. كل عملية تقدير تُسجَّل كصفّ DiagnosticSession إلحاقي فقط. القراءات/الكتابات محصورة بالمؤسسة؛ وتتطلّب صلاحية USE_DIAGNOSTIC_ENGINE، ولا يمكن لرمز الطالب أن يُقدِّر إلا إجاباته هو.
  • حتمي وقابل لإعادة التشغيل (V-6). المدخلات نفسها ← θ متطابقة حرفيًا إلى 4 منازل عشرية. كل جلسة تُجمِّد صعوبات الأسئلة المستخدمة فعليًا (resolvedDeltas)، فتُعيد POST /api/engine/replay/:sessionId إنتاج التقدير الأصلي دائمًا — حتى بعد أن يُحدِّث خطُّ المعايرة تلك الصعوبات لاحقًا.
  • صعوبة بمسارين. تُعتمَد الصعوبة المقيسة للسؤال متى بلغ ≥300 إجابة حقيقية (وطابق إصدار المعايرة المثبَّت للجلسة)؛ وإلا تُستخدم الصعوبة المقدَّرة الحتمية ويُوسَم الصفّ مبدئيًا.
  • لا نموذج لغوي إطلاقًا (V-5). مسار التقدير بأكمله دالة حتمية صرفة — يغطّيه فحص CI لمنع النماذج اللغوية + تجسّس تكاملي. عند نقص البيانات ← newTheta:null (استجابة 200، أي «لا تقرّر بعد»).
  • القراءات: GET /api/engine/sessions/:id + GET /api/engine/sessions/by-student/:studentId. تقدير الموجة الأولى بديل حتمي مؤقّت، لا إحصاء راش الحقيقي — يحلّ المحرّك الإحصائي الحقيقي لاحقًا (خطّ المعايرة) دون أي تغيير في العقد.

سجلّ فحوصات الجودة في النظام — 2026-06-20

أربع عمليات تحت وسم qa الجديد (يصبح العدد 92). يسجّل سجلٌّ من 32 فحصًا الثوابتَ الأمانية الشاملة التي تفرضها محرّكات القرار والتدخّل والمحتوى فعلًا — تتولّى هذه الطبقة التسجيل والتوجيه فقط؛ لا تضيف أي منطق فحص جديد.

  • مراقبة للمشرفين/الهندسة فقط. تُعيد GET /api/qa/checks سجلّ الـ32 فحصًا؛ وتُدرج GET /api/qa/runtime-alerts التنبيهاتِ الموجَّهة في وقت التشغيل لمؤسستك (بترشيح حسب severity أو النافذة الزمنية أو qaCheckId)؛ وتُلخّصها GET /api/admin/qa/audit-summary حسب الفحص والخطورة. وتتطلّب جميعها صلاحية VIEW_QA_REGISTRY (أو المشرف الأعلى/الواجهة الخلفية) — ولا يصل إليها رمز معلّمة أو طالب أبدًا.
  • توجيه حتمي. يُوجَّه فشلُ فحصٍ في وقت التشغيل وفق خطورته المسجَّلة فقط — الحرِج يظهر على لوحة المعلّمة وينبّه قناة التنبيه، والعالي ينبّه الهندسة، والمتوسّط يسجّل التنبيه، والمنخفض يسجّل فقط. ويُثبَّت على كل تنبيه موجَّه نسخةُ السجلّ والقاعدة لإعادة التشغيل.
  • لا حوض تنبيهات جديد. تُلحَق التنبيهات الموجَّهة بسجلّ تنبيهات المنصّة القائم (إلحاق فقط)؛ ولا تُعيد قراءةُ الـQA أي صفوف تنبيه غير خاصة بالـQA.
  • جديد — POST /api/admin/qa/checks-set (نشر نسخة جديدة من السجلّ). للمشرف الأعلى/الواجهة الخلفية فقط. يماثل نشر إعدادات الحزمة ومحرّك القرار: يأخذ مجموعة فحوص مرشَّحة مع موافقة الشريك وإقرار الفروقات، ويُجري بوّابة اكتمال (وجود الفحوص الـ32 جميعها، وقابلية كل أمر للتشغيل، وأمان كل رسالة عربية)، ثم يُعيد النسخة المرتقَبة — رافضًا النقصَ أو غياب الموافقة أو عدم إقرار الفروقات.
  • جديد — حارس الإفراط في القياس QA_032. تنبيهٌ متوسّط الخطورة (وليس حجبًا أبدًا) يُطلَق عندما يُقاس الطالب مرّاتٍ كثيرة في فترة قصيرة — تُسجَّل جلسة القياس دائمًا، ويكتفي التنبيه بتذكير المعلّمة بالتدريس قبل قياسٍ إضافي. عتبةُ الإفراط ونافذتُه قابلتان للضبط من الشريك (قيمٌ افتراضية مؤقتة بانتظار جلسة الشريك في يونيو).

طبقة سلامة اللغة — 2026-06-20

ستّ عمليات جديدة تحت وسم language-safety الجديد (يصبح العدد 102). طبقةُ إعادة الصياغة الحتميّة القائمة على القواعد، توضَع أمام كل نصٍّ يعرضه النظام أو يحفظه أو يطبعه — تحوّل العبارات السريريّة/عبارات العجز إلى لغة نموّ، وتحذف مسمّيات الأطر الدوليّة، وتطبّق مرشّحًا أكثر صرامةً لجمهور أولياء الأمور. هي ليست نموذجًا لغويًا (V-5) ولا تغيّر أي قيمة قياس — بل تغيّر طريقة وصفها فقط (V-3/V-12).

  • تحقّقي من أي نص. تُشغّل POST /api/language-rules/validate الدالّة sanitize(text, appliesTo, profileKey?) وتعيد النصّ الآمن + القواعد التي طُبّقت + رقم نسخة مجموعة القواعد (إعادة تدقيق V-6). المستويات: ui / reports / parent / parent_stricter / teacher_note / student / admin. ويمنع مستوى parent_stricter الدرجاتِ الرقميّة والمعرّفاتِ الداخليّة؛ وتُطبَّق طبقة do_not_say الخاصّة بكل ملف عند العرض.
  • إدارة القواعد للمشرف. تُعيد GET /api/language-rules مجموعة القواعد الفعّالة (تُستهلك عند تحميل النصوص في التطبيق ومولّد PDF)؛ وتُدرِج POST /api/language-rules نسخةً جديدة (إلحاق فقط — يُعطَّل الصفّ السابق ولا يُعدَّل في مكانه)؛ وتُحيل PATCH /api/language-rules/{id}/deactivate صفًّا إلى التقاعد.
  • أعلام سياق مضبوطة فقط. تُرفِق POST /api/students/{id}/context-flag علمًا مضبوطًا من قاموسٍ مغلق — لا يوجد حقل نصّ حرّ في الجسم؛ والعلم المحظور/الممنوع يُعيد 422 context_flag_blocked ويُسجّل قيدَ تدقيقٍ أمنيًّا يحفظ الطولَ فقط (لا يُخزَّن أي نصّ عن الطفل أبدًا). وتُعيد GET /api/students/{id}/context-flags الأعلامَ المسجّلة بمسمّياتها الآمنة (للمعلّمة/المشرف فقط).
  • الفشل المغلق. أي عرضٍ يتعذّر فيه تحميل مجموعة قواعد فعّالة يرفض بدلًا من إخراج نصٍّ غير مُرشَّح.

العمود الفقري للمعايير + الإدارة الديناميكية لمستويات الكفاية — 2026-06-20

ثماني عمليات جديدة تحت وسم standards الجديد (يبلغ عدد العمليات الآن 110). هكذا تتحوّل الدرجة الخام إلى «ضمن المسار / يقترب / دون المستوى / حرِج» — وكيف تُدار هذه العتبات دون تعديل الشيفرة.

  • مفردات حُكمٍ واحدة، ولا درجة إجمالية أبدًا (V-3). كل مقياس يُحَلّ إلى إحدى القيم meets / approaching / below / severe / not_assessed. القيمة not_assessed لا تُعامَل كصفر أبدًا وتُستبعَد من أي تجميع. لا توجد «درجة قراءة إجمالية» في أي مكان.
  • العتبات تعيش في البيانات، مُصدَّرة، وقابلة للتبديل. يسير GET /api/standards/benchmark-profiles/resolve عبر سلسلةٍ حتميّةٍ من ثلاث خطوات (مطابقة دقيقة ← افتراضي للدولة ← احتياطي عالمي) ولا يُعيد قيمةً فارغةً أبدًا — فصفٌّ عالميٌّ مزروعٌ يضمن الحلّ. يدير المشرفون العامّون الصفوف تحت /api/admin/benchmark-profiles؛ والتفعيل تبديلٌ ذرّيٌّ (تُعطَّل النسخة القديمة وتُفعَّل الجديدة، وكلاهما مُدقَّق).
  • التاريخ لا يتبدّل أبدًا (V-6). تثبّت الجلسةُ نسخَ معاييرها عند البدء؛ والتبديل اللاحق لا يغيّر أحكام الجلسات الجارية، وكل نتيجةٍ مخزَّنةٍ تُعيد اشتقاق حالتها الأصلية إلى الأبد.
  • صفر تسميات أُطُر دولية (FR-STD-1). المعايير الدولية (المستخدَمة فقط لمعايرة عتبات العربية) تُجرَّد عند طبقة التسلسل — لا تصل أبدًا إلى واجهة معلّمٍ أو مديرٍ أو وليٍّ أو طالب. لوحة المدير تتحدّث بمسمّيات مؤشّرات المنهاج العربية فقط.
  • قراءات المدير + نموذج تقرير الوزارة. يُعيد GET /api/principal/schools/:id/{overview,heatmap} مقاييس مؤشّرات المنهاج + مؤشّر صحّة القرائية للمدرسة المحسوب (دون بيانات شخصية). تقرير الوزارة بنقرةٍ واحدةٍ مُسجَّلٌ كنموذج عقدٍ للموجة الأولى (501)؛ ويصل ملفّ PDF في الموجة الثانية.

أرقام مستويات الكفاية مملوكةٌ للشريك (مستخرَجة من مصنّف v3.3 — الأردن وفلسطين)؛ وصفوف الاحتياطي العالمي + صياغة مسمّيات مؤشّرات المنهاج مُعلَّمةٌ كقيمٍ افتراضيةٍ مؤقّتةٍ بانتظار جلسة الشريك في 25 يونيو. الترحيل: 20260620150000_wp_std_be. وثيقة المتطلّبات: 12-benchmarks-and-country-config (FR-STD-1..6).

سير عمل تفعيل المعلّمة — 2026-06-20

سبع عمليات جديدة تحت وسم workflow الجديد (يصبح العدد 88). يقود سيرُ عملٍ من 17 خطوة المعلّمةَ عبر المراجعة ← التجميع ← التفعيل ← المتابعة ← القرار، مُركّبًا محرّكات الحزمة والتجميع والمتابعة في تدفّقٍ موجَّه واحد.

  • المعلّمة تقرّر، والنظام يمنع الخطوات غير الآمنة (V-12). لا تُفعّل POST /api/workflow/activate خطّةً حالتها do_not_decide_yet، وتُرفض أي نقلة حياة غير صالحة (409). ولا يُغيَّر مستوى RTI بأي إجراء سير عمل.
  • حواجز الأمان عند الحدود. الأدلة غير الكافية ← مطالبة، لا تفعيل؛ وتنبيه التراجع الحاد المفتوح يفرض مسار المراجعة (تحلّه POST /api/workflow/review بتصرّفٍ صريح من المعلّمة)؛ والطالب DATA_INCOMPLETE يُستبعد من التفعيل المجمّع.
  • التعديلات لكل عضو مقصودة. أي تغيير لمستوى السقالة / التسليم / الجدولة عن التوصية يتطلّب تأكيدًا صريحًا (وإلا 409) ورمز سببٍ مضبوط — لا نصّ حر.
  • لا مسار بيانات جديد. تمرّ آثار سير العمل عبر مسارات الكتابة القائمة (التفعيل/التجميع/المتابعة)؛ وتُختم خطوة سير العمل المُطلِقة على تاريخ الإسناد. وتحفظ POST /api/workflow/save-draft سير عملٍ قيد التقدّم (7 أيام)، يُستعاد عبر GET /api/workflow/draft/:teacherId/:classId.
  • أيضًا: لم يعد ردّ تنبيه التراجع الحاد يتضمّن contextFlagId — يُسجَّل علم سياق الرفض في سجلّ أعلام السياق فقط (الموطن المعتمد الوحيد).

السجلّات والرصد — 2026-06-20

عمليتان جديدتان تحت وسم logging الجديد (يصبح العدد 81). تُكمل عقد السجلّات في المنصّة فوق نواة المُسجِّل وربط المعرّفات الذي شُحن سابقًا.

  • POST /api/logs/client — يُرسل المتصفّح سجلّات التحذير والخطأ إلى الخادم (تحذير/خطأ فقط؛ بحدّ دفعة واحدة لكل مستخدم كل 5 ثوانٍ). يَختم الخادم userId/orgId/ts من الهويّة الموثّقة — لا من جسم الطلب أبدًا — فلا يستطيع العميل تزييف صاحب السطر أو مؤسّسته. ونقطة الاستقبال لا تُسجّل نفسها عمدًا (حارس الحلقة اللانهائية).
  • GET /api/health/log-level — فحص تشغيلي بلا مصادقة يُعيد مستوى السجلّ العام الفعّال وأي تجاوزات لكل وحدة، ليتأكّد المشغّلون ممّا يعمل به النشر دون إعادة نشر.
  • لا تغيير في المخطّط. السجلّات شأن تشغيلي؛ وحفظ سجلّات العميل سؤال للموجة الثانية.

خدمة تسليم المهام — 2026-06-20

أربع عمليات جديدة تحت وسم delivery الجديد (يصبح العدد 79). هذا ما يحدث وقت الطالب: تختار المنصّة العنصر المُؤلَّف مسبقًا المناسب وتقدّمه كما هو مخزَّن تمامًا — ولا تُركّب المحتوى أثناء التشغيل أبدًا.

  • الاختيار والتقديم. تُرشّح POST /api/delivery/task بنك العناصر التشغيلي وفق (المهارة الفرعية × مستوى السقالة × نمط المهمة × الصعوبة × اللهجة)، وتختار حتميًا، وتُعيد العنصر المخزَّن. وهي نقطة التقديم الوحيدة التي يستدعيها كل مستهلك (التشخيص، التدريب، عيّنات المتابعة، نموذج السقالة المتكامل) لكل مهمة.
  • لا ارتجال. المجموعة الفارغة من المرشَّحين تُعيد 200 { served: null, log.reason: "no_eligible_item" } — لا خطأ ولا بديل صامت أبدًا. المُستدعي يقرّر تجربة الاستخدام؛ وتتجمّع الفجوة في GET /api/admin/delivery/gap-summary (حسب المهارة الفرعية × المستوى × النمط) لتخطيط حجم المحتوى.
  • المستوى والنمط مُرشِّحات، لا مفاتيح عرض. متغيّرات كل مستوى صفوف مخزَّنة مستقلة؛ وعيّنات المتابعة تتجاهل المستوى ولا تُظهر تلميحات أو تغذية راجعة أثناء العيّنة (سلامة العيّنة). ولا يرى الطالب أبدًا تسمية ملف أو حزمة أو مستوى.
  • حتمي وقابل للتدقيق. كل تقديم يكتب صفًّا إلحاقيًا في served_task_instance مفتاحه taskInstanceId من نوع UUID (رمز ربط ورقة العمل عبر QR)، يُثبِّت مدخلات اختياره؛ وتُعيد POST /api/admin/delivery/dry-run-replay التأكيد على الاختيار نفسه (V-6) دون أن تكتب شيئًا. ولا نموذج لغوي على مسار التقديم (V-5).
  • نافذة “المُقدَّم حديثًا” (الافتراضي للموجة الأولى 7 أيام) ونصوص التغذية الراجعة لكل نمط مملوكة للشريك (25 يونيو)؛ واستبدال المعلّمة بمستوى أدنى مؤجَّل (الافتراضي no_eligible_item).

قواعد متابعة التقدّم — 2026-06-20

ثلاث عمليات جديدة تحت وسم monitoring الجديد (يصبح العدد 75). تتابع المنصّة الآن ما إذا كان التدخّل ناجعًا وتطلق مراجعةً عند تراجع الطالب.

مواءمة المواصفات وإصلاحات — 2026-06-20

جولة صيانة — دون عمليات جديدة (يبقى العدد 75). تغييران ظاهران لمستهلك الواجهة، إضافةً إلى تصحيحاتٍ في مجموعة المواصفات وفي الاختبارات.

  • المؤسّسات تُعيد الآن createdBy. يتضمّن كل ردٍّ من GET /api/organizations / …/{id} حقل createdBy (مُعرّف المستخدم للمشرف الأعلى الذي أنشأ المؤسّسة) — القيمة كانت مُخزّنة أصلًا عند الإنشاء، وأصبحت الآن مكشوفة (FR-TEN-1). وحُدِّث مخطّط OrgResponse في مرجع الواجهة وفقًا لذلك.

  • تصحيح إشارة حالة المجال. تُعيد GET /api/sse/students/{id}/domain-status الآن إشارة doNotDecideYet المُخزَّنة بدل اشتقاقها وقت القراءة، التزامًا بعقد المستهلك FR-SSE-16 «مُخزَّنة لا تُشتَقّ» (وهو ما كان يحدث أصلًا في نقطة حالة المهارة). وعلى المستهلكين ما زال يلزم التحقّق من doNotDecideYet قبل التصرّف.

  • مسارات التصنيف توثّق 401. أصبحت مسارات القراءة الأربعة (GET /api/sub-skills و…/{id} و /api/domains و/api/skill-dependencies) تُصرّح بردّ 401 (غير موثَّق) الذي كانت تُعيده أصلًا.

  • داخلي فقط. يكتسب gateway_priority_config عمود تدقيق published_at (ترحيل 20260620120000)؛ ومواءمات في مجموعة المواصفات داخل 11-skills-taxonomy (15 نوع عنصر نشط، سطح واجهة التصنيف بأربعة مسارات، عدد SENT/SYN‏ 12، تعريف العرض العادي)، وتصحيح مرجعَي FR-ID متقاطعَين، وتغطية اختبارية إضافية لفروع فشل فحوص request-id والإلحاق-فقط / context-flag.

  • تسجيل أدلة التقدّم. تُسجّل POST /api/monitoring/evidence أنواع الأدلة غير-CBM (فحص سريع، روبرِك، ملاحظة المعلّمة، ورقة عمل، اتجاه رقمي) مع ظروف التطبيق؛ السجلّ إلحاقي فقط ويُطلق إعادة حسابٍ حتمية مثبَّتة على إصدار القاعدة (V-6).

  • خمس قواعد سلامة تحكم كل قرار. الأدلة غير الكافية أو غير القابلة للمقارنة ← do_not_decide_yet؛ لا قرارات من نقطة واحدة؛ لا تُقارَن إلا الفحوص المتماثلة. التراجع الحاد (هبوط ≥20% عبر جلستين متماثلتين) يطلق مراجعةً فوريّة — دون إخفاقٍ تلقائي أو خروجٍ تلقائي أو تغيير مستوى RTI (المعلّمة هي من تقرّر).

  • الحالة والتنبيهات. تُعيد GET /api/monitoring/status/{bundleAssignmentId} الحكم الحالي + إصدارات القواعد المثبَّتة؛ وتسرد GET /api/monitoring/alerts تنبيهات التراجع الحاد المفتوحة. ولا يُغلَق التنبيه إلا بتصرّفٍ صريح من المعلّمة عبر رمز سببٍ مضبوط — لا نصّ حر.

  • إغلاق جسر سلامة التجميع الذكي. يقرأ التجميع الآن تنبيه التراجع الحاد الحقيقي (كان يفشل-مفتوحًا)، فيُوجَّه الطالب المتراجع إلى مراجعة فردية ويُبقى خارج المجموعات.

التجميع الذكي والتفعيل المجمّع — 2026-06-19

ثلاث عمليات جديدة تحت وسم cluster الجديد (يصبح العدد 72). تجمّع المعلّمة الطلاب الذين يحتاجون الدعم نفسه في مجموعات صغيرة وتفعّل المجموعة كاملةً بإجراءٍ مؤكَّد واحد.

  • تجميع حتمي. تجمّع POST /api/cluster/recompute/:classId الصف بمطابقة من 5 مفاتيح (الحزمة + المرساة + مستوى السقالة + نمط التسليم المتوافق + كفاية البيانات)؛ ويندمج المستوى 1 + المستوى 2 للتسليم بقيادة المعلّمة فقط؛ الحد الأدنى لحجم المجموعة 2 (مفتاح المدرسة 3–5). النتائج إلحاقية فقط ومثبَّتة على إصدار قاعدة التسلسل (حتمية V-6)، مع احتفاظ 60 يومًا.
  • استثناءات السلامة صارمة. الطالب DATA_INCOMPLETE / do_not_decide_yet ← قائمة “بيانات إضافية مطلوبة”؛ والطالب ذو التراجع الحاد ← مراجعة فردية. ولا يُجمَّع أيٌّ منهما أو يُفعَّل ضمن مجموعة أبدًا.
  • التفعيل المجمّع (V-12، يعيد استخدام مسار الكتابة الوحيد). تتطلّب POST /api/cluster/bulk-activate تأكيد المعلّمة الصريح، وتنشئ إسناد كل عضو عبر الكاتب نفسه الذي يستخدمه التفعيل الفردي (مختومًا بمعرّف المجموعة)؛ الكل-أو-لا-شيء (عضو مستثنى ← 422)، وعديم التأثير عند التكرار، و409 عند مجموعة قديمة. ويبقى التمايز في إسناد السقالة لكل طالب فقط.
  • معاينة. تُعيد GET /api/cluster/student/:studentId/preview المجموعة الحالية للطالب + توزيع السقالة لكل مستوى؛ دون أي تفاصيل تظهر للطالب.
  • يقرأ استثناء acute_regression جسرًا يفشل-مفتوحًا حتى تنتج WP-PROG-MON-BE الإشارة؛ ومُجدوِل إعادة الحساب الليلي جسرٌ (تُشحن دالة إعادة الحساب عديمة-التأثير الآن).

فهرس حزم التدخّل — 2026-06-19

يصل مُوصِّي الحزم. إحدى عشرة عملية جديدة تحت /api/bundles و/api/assignments و/api/students/:id و/api/admin/bundle-* (يصبح العدد 69). يحوّل ملف الطالب إلى حزمة تدخّل واحدة موصى بها من فهرس مغلق يضم 20 حزمة، ويُسنِد دعم السقالة، ويسلّم المعلّمة تفعيلًا بنقرة واحدة.

  • توصية حتمية. تربط POST /api/bundles/recommend الملف النشط (الرمز الأساسي + المحرّك/المعدّل) عبر خريطة الملف↔الحزمة المكوّنة من 21 صفًّا إلى حزمة واحدة بالضبط — مهارة مرساة + 1–2 خيط داعم + جسر أصول مدعوم بالبيانات، مع بقاء المرساة دائمًا أكبر حصة جرعة.
  • الحزمة توصية لا تفعيل تلقائي (V-12). تتطلّب POST /api/students/:id/activate-bundle المعلّمة؛ ودورة حياة الإسناد ذات الـ14 حالة إلحاقية فقط ومُظلَّلة بالتاريخ. تستخدم التعديلات (PATCH …/scaffold-assignment | …/delivery | …/schedule وPOST …/context-flag) رموز أسباب مضبوطة فقط — لا نصّ حر — ولا يمكن لأي تعديل تغيير مستوى RTI إطلاقًا.
  • توقّف آمن. لا ملف نشط / DATA_INCOMPLETE / do_not_decide_yet ⇒ blocked_insufficient_evidence مع إجراء بيانات تالٍ موصى به، لا حزمة. ولا يمكن لأي دور التجاوز.
  • لا يرى الطالب أبدًا معرّف الحزمة أو اسمها أو رمز الملف أو وسم مستوى السقالة — يُحذف عند التسلسل.
  • المشرف. POST /api/admin/bundle-config-sets (نشر + بوابة اكتمال)؛ وPOST /api/admin/bundle-replay (تشغيل تجريبي للفرق V-6 دون كتابة). تصل نقاط التجميع الذكي والتفعيل المجمّع مع WP-CLUSTER-BE.

تحديد ملف الطالب التعليمي — 2026-06-19

يصل محرّك الملفات التعليمية. ست عمليات جديدة تحت /api/profile و/api/admin/profile-* (يصبح العدد 58). يركّب مخرجات محرّك حالة المهارة في ملف تعليمي واحد مُسمّى لكل طالب لكل نافذة قياس، مع سرديات عربية مكتوبة بالقواعد لكل جمهور.

  • قراءة ملف الطالب. ترجع GET /api/profile/{studentId}?window= الإسناد النشط أو المعلّق — الرمز الأساسي والمحرّكات والمعدّلات والثقة وتثبيتات إصدارات القواعد وassignmentStatus (ليعرض العميل مسار «معلّق ← تأكيد»). وعند نقص الأدلة تُرجِع حارس DATA_INCOMPLETE المنظَّم (200)، لا ملفًا.
  • السرديات لكل جمهور وآمنة. ترجع GET /api/profile/{studentId}/narrative?audience=teacher|parent|admin النصّ المُصفّى مسبقًا بفلتر سلامة اللغة. audience=student مرفوض (422) — لا يتلقّى الطالب أبدًا رمز ملف أو أي درجة رقمية؛ ولا تحمل سردية ولي الأمر أي معرّفات داخلية.
  • المعلّمة تقرّر (V-12). يبدأ كل تحديد جديد بحالة pending_teacher_review؛ وتقوم POST /api/profile/{studentId}/review-resolution مع { outcome: confirm } بترقيته إلى active. ملف أساسي واحد نشط لكل نافذة؛ وكل تغيير صفّ جديد لا يُعدَّل.
  • توقّف آمن. إذا كانت أي مهارة مساهِمة do_not_decide_yet أو نقصت تغطية مجال مطلوب، لا يُكتب ملف — ولا يمكن لأي دور تجاوز ذلك.
  • المشرف. تُشغّل POST /api/admin/profile-catalog/publish بوابة اكتمال الفهرس (لكل رمز أساسي تغطية CDP/PGA/SPOT)؛ وPOST /api/admin/profile-replay تشغيل تجريبي للفرق (V-6) دون أي كتابة.

تصنيف المهارات: إضافة VOCAB-C06 (79 مهارة) — 2026-06-19

اعتماد الشريك لربط معرّفات المهارات الفرعية. يرتفع فهرس المهارات من 78 إلى 79: تُرجِع GET /api/sub-skills الآن المهارة VOCAB-C06 (فهم المرادفات) ضمن مجال المفردات VOCAB. لا عمليات جديدة (يبقى العدد 52).

  • مهارة جديدة VOCAB-C06 فهم المرادفات. يغطّي مفهوم VOC_REL الآن الأضداد (VOCAB-C05) والمرادفات (VOCAB-C06) معًا.
  • توحيد أسماء المؤشرات. مؤشر الكتابة/الإملاء أصبح WR_SP_ALERT (بدل WRITING_SPELLING_ALERT)؛ وAR_LETTER_CONFUSION_FLAG يقتصر على الخلط البصري/الإملائي فقط.
  • نطاق الميزات العربية (المرحلة الحالية). تأتي إشارات المدّ/الحركات القصيرة من بنود مكتوبة/بصرية فقط (لا من نوع خطأ القراءة الجهرية)؛ ولا تفتح الهمزة/الشدة/التنوين أي حزمة أو تنبيه في هذه المرحلة.

محرّك حالة المهارة — 2026-06-19

يصل محرّك القرار. سبع عمليات جديدة تحت /api/sse (يصبح العدد 52): خمس نقاط قراءة فقط للمستهلكين ونقطتان للمشرف.

  • قراءة الحالة التفسيرية للطالب. ترجع GET /api/sse/students/{id}/skill-status و/domain-status أحدث لقطة لكل (مهارة فرعية|مجال، نافذة قياس)، وتحمل كل منها معرّفات وإصدارات القواعد المطابِقة (لإعادة التشغيل) وإشارة doNotDecideYet. وتغذّي /pattern-classifications و/behavior-log شرح «لماذا هذه الحالة» وشاشة مراجعة المعلّمة. جميعها محصورة بالمستأجِر، للقراءة فقط، بصلاحية VIEW_STUDENT_PROGRESS — ولا تُعرض أي قيمة حالة للطالب إطلاقًا.
  • do_not_decide_yet توقّف صارم. حين تكون الأدلة قليلة أو متضاربة أو متدنّية الجودة يرفض المحرّك الحسم ويُصدر الإشارة؛ على المستهلكين التوقّف فورًا (لا ملف، لا حزمة، لا تنبيه، لا حدث إتقان) — ولا يمكن لأي دور تجاوزها.
  • تُحسب الحالة في الخادم لا عند الطلب. لا توجد نقطة «احسب الآن» للعميل؛ تُعاد الحالة عند وصول دليل جديد. تُرجع القراءات اللقطة المخزّنة — ولا يعيد المستهلكون اشتقاقها.
  • المشرف (نشر القواعد). POST /api/sse/admin/rules/{layer}/publish (تحقّق من المخطّط + استثناء الدقّة العربية + كشف الصفوف المتداخلة + فرق التشغيل التجريبي، بحاجة موافقة الشريك) و POST /api/sse/admin/dry-run-replay. نشر إصدار قاعدة جديد لا يغيّر اللقطات القائمة بأثر رجعي — تبقى مثبّتة على إصدار وقت حسابها.

مُعرِّف ربط الطلب — 2026-06-19

صارت كل استجابة تحمل مُعرِّف ربط X-Request-Id، ويقبل الخادم مُعرِّفًا واردًا. لا عمليات جديدة؛ العدد كما هو (45).

  • صار X-Request-Id مقبولًا واردًا. إذا أرسلت ترويسة X-Request-Id مطابقة للنمط ^[A-Za-z0-9_-]{8,128}$، يعتمدها الخادم حرفيًا في الاستجابة؛ وإلا يولِّد واحدًا (req_<hex>). أرسِل مُعرِّفك الخاص لربط أثر العميل بسجلات الخادم لذلك الطلب.
  • X-Request-Id مكشوف عبر CORS. صار بإمكان عملاء المتصفح على أصل مسموح قراءة الترويسة من الاستجابة (Access-Control-Expose-Headers: X-Request-Id) — سجِّلها في جهة العميل واذكرها في بلاغ الخطأ.
  • داخليًا (دون تغيير في العقد): يُربط المُعرِّف تلقائيًا بكل سطر سجل في الخادم ويُحفظ على صفوف النشاط/التدقيق التي ينتجها الطلب (أحداث المصادقة، تجاوز المشرف الأعلى، سجلات استيراد العناصر وδ_prior)، فيتمكّن الدعم من الانتقال من مُعرِّف مُبلَّغ ← سجلات الخادم ← تغييرات قاعدة البيانات لطلب واحد.

المحتوى — 2026-06-19

إضافات على محتوى بنك العناصر ومخططه تمهيدًا للتجربة الميدانية. لا عمليات منشورة جديدة؛ العدد كما هو (45) — إذ تبقى واجهات بنك العناصر والاستيراد غير منشورة بعد.

  • مجموعة محتوى بذرية مُتحقَّق منها. صار لدينا بنك عناصر مُؤلَّف دون اتصال ومُتحقَّق منه — 645 عنصرًا
    • نصّان قرائيّان عبر المجالات الرقمية السبعة، وكل مهارة قابلة للتأهيل ممثَّلة بـ 8–12 عنصرًا، وجميعها يجتاز بوابة الاستيراد. العناصر بحالة source='offline_generated' وstatus='draft' (لا تُقدَّم لطالب حتى موافقة خبير المادة). قِيَم صعوبة العناصر (δ_prior) حقيقية بالكامل (معجم SAMER v2 + CAMeL).
  • إضافات على المخطط (بنك العناصر). حقل استيراد اختياري جديد image_url وعمود imageUrl لعناصر مطابقة الصورة، وتوسيع مفردات distractor_type المضبوطة من 13 إلى 19 (أُضيف agreement_error وwrong_part_of_speech وwrong_function_word وin_text_wrong_detail وwrong_syllable_count وwrong_sound_position) مع توسيع مصفوفة توافق الاستيراد لتطابقها. لا تغيير على أيّ مسار منشور أو شكل طلب أو شكل استجابة.

صيانة — 2026-06-18

تمريرة تصحيحية مدفوعة بالمهام الدورية — أُغلقت دفعة من ملاحظات مراجعة الكود وانحراف المواصفة. لا عمليات جديدة؛ العدد كما هو (45).

  • حذف الصف أصبح حذفًا ناعمًا (soft-delete). نقطة DELETE /api/classes/:id لم تتغيّر للمستهلِك (الطلب نفسه والاستجابة { ok: true } نفسها)، لكن الصف وإسنادات معلّميه وطلابه تُحفَظ الآن للتدقيق بدل إزالتها. لم يَعُد الصف المحذوف يظهر في GET /api/classes ولا GET /api/classes/:id (404) ولا في التجميع المؤسسي ولا في استعلامات القوائم والإسناد. ولا يزال حذف صفٍّ به طلاب نشِطون مرفوضًا (409). ← راجع المفاهيم الأساسية.
  • تحصين داخلي (لا تغيير في عقد الـ API): إحكام نطاق المدير/المعلّم على الوصول إلى الصفوف والطلاب والمنسقين؛ وصحّة تصعيد قفل محدّد المعدّل؛ وسلامة استيراد العناصر (كتابة ذرّية، تحقّق لكل صف، حماية كتابة العناصر العامة)؛ وحجب حقول السجلّات. رموز الأخطاء وأشكال الطلب والاستجابة لم تتغيّر.

تصنيف المهارات الفرعية — 2026-06-18

يُشحَن تصنيف مهارات محو الأمية العربية كبيانات مرجعية عامة — 4 عمليات قراءة ضمن الوسم الجديد sub-skills، فيصير المجموع 45 عملية منشورة.

  • GET /api/sub-skills — قائمة مُقسَّمة لجميع المهارات الـ 78 الفرعية مع مجالها ونطاقها الصفّي ونوع تقييمها وعلامتي البوابة/المهارة الأساسية. (ارتفعت إلى 79 بإضافة VOCAB-C06 المذكورة أعلاه)
  • GET /api/sub-skills/{id} — صف مهارة واحدة بمعرِّف CUID.
  • GET /api/domains — المجالات التسعة لمحو الأمية العربية (الوعي الصوتي، فك الترميز، طلاقة القراءة، الفهم، المفردات، وغيرها).
  • GET /api/skill-dependencies — روابط المتطلّبات السابقة بين المهارات.

تتطلّب النقاط الأربع مصادقة وسياق مستأجِر؛ وصلاحية VIEW_OWN_PROFILE تُمتلَك من قِبَل كل الأدوار (معلّم، مسؤول، مدير مدرسة، منسّق، ولي أمر، طالب)، فالتصنيف متاح لجميع المستخدمين المصادَق عليهم.

أساس بنك العناصر — 2026-06-18

واجهة بنك العناصر متاحة — 12 عملية ضمن الوسم items. هذه مسارات غير منشورة مقيَّدة بـ RUN_BACKOFFICE (للمكتب الخلفي/خبير المادة فقط)؛ ولا تؤثّر في عدد العمليات المنشورة (45).

  • القراءة — GET /api/items، GET /api/items/{id} (?view=authoring للصف التأليفي الكامل)، GET /api/item-types، GET /api/item-types/{code}/distractor-compat.
  • مسار الاستيراد — POST /api/items/import، GET /api/items/import، GET /api/items/import/{batchId}، POST /api/items/import/{batchId}/approve.
  • دورة الحياة — POST /api/items/{id}/sme-approve، POST /api/items/{id}/promote، POST /api/items/{id}/retire.
  • قِيَم الصعوبة المسبقة — GET /api/expected-difficulty/log (سجل تدقيق δ_prior الحتمي).

1.0.0-phase0

الموقع الأوّل. يوثّق WP-A1 المصادقة + WP-A2 البنية المستأجِرة + WP-A3 إدارة المستخدمين — 41 عملية عبر الوسوم auth وtenancy وusers وsystem.