---
title: "جسر القياس"
url: https://docs.growamal.com/ar/guides/measurement-bridge/
language: ar
---

# جسر القياس

جسر القياس هو الوصلة بين قلب القياس وسطوح التقارير. يُحوِّل التشخيص المُنتهي إلى حالات
per-skill وper-domain وحالات الألواح الكلية التي يقرأها كل تقرير معلم وكل PDF للوالد وكل
ملخص لوحة إدارة وكل تجميع متعدد المدارس. وهو إسقاط من جانب الخادم مُعلَّق على انتهاء
التشخيص، ولا يُدخل أي مسارات جديدة.

قبل وصول الجسر، كان `finishSession` يكتب θ لكل مهارة فرعية في `student_assessment_result`
ثم يتوقف. لم يكن أي شيء يكتب `evidence_row`، ولا يستدعي إعادة حساب حالة المهارة، ولا يكتب
`macro_domain_status_snapshot` إطلاقاً، فكان كل سطح للتقارير والوالد ولوحة الإدارة
ومتعدد المدارس يقرأ جدولاً فارغاً في الإنتاج. يُغلق الجسر تلك الفجوة بإصدار الأدلة
واللقطات لحظة انتهاء التشخيص.

## الفجوة التي يُغلقها الجسر

يُغلق الجسر شَقَّين تُركا مفتوحَين بعد انتهاء التشخيص.

1. لم تكن نتائج θ تُحوَّل إلى `evidence_row`. لم يكن لدى محرك حالة المهارة أي دليل لكل مهارة
   فرعية يُعيد الحساب منه.
2. كتب محرك القرار كل `domain_status_snapshot` لكن لم يكن أي شيء يجمع الألواح الكلية الستة،
   فظل الجدول الكلي فارغاً.

تبقى θ بالضبط حيث كانت: مُخزَّنة على `student_assessment_result` ويستهلكها بَذر التدرب.
الجسر إصدار موازٍ، لا بديل. لا يُحرِّك θ ولا يُعيد تسجيل أي شيء.

## سلسلة التحفيز

يجري التدفق المُطبَّق بهذا الشكل:

```
finishSession (modules/session/diagnostic.orchestrator.ts)
  ├─ (in the finish tx, first-finish gated) writeScreeningEvidence → evidence_row {correct,total}
  └─ (AFTER the tx commits) projectBridge (modules/sse/bridge/diagnostic-bridge.ts)
        ├─ recomputeForEvidence × N sub-skills → skill_status_snapshot + domain_status_snapshot
        └─ recomputeMacroForStudent ONCE       → macro_domain_status_snapshot (6 tiles + GLOBAL)
```

حقائق رئيسية:

- يجري الجسر **بعد** إيداع معاملة الانتهاء، لا متداخلاً داخلها. والسبب اثنان. يجب أن يكون
  `evidence_row` دائماً قبل أن تُعيد `recomputeForEvidence` قراءته، ويجب ألا يمتد قفل
  الانتهاء على `(org, profile.id)` ليشمل قفل حالة المهارة على `(org, student, window)`.
- السلسلة كلها متزامنة وداخل العملية. لا يوجد طابور ولا وسيط، لأن التجربة تعمل على نحو 30
  مدرسة.
- العطل بين الإيداع والجسر **يُصلح نفسه عند إعادة الانتهاء**، لأن كل كتابة حتمية مُثبَّتة
  بالإصدار.
- المرور الكلي **مُهدَّأ (debounced)**: تدفع N مهارة فرعية N إعادة حساب للمهارة والنطاق،
  لكن يجري مرور كلي واحد بالضبط على أحدث المُغذِّيات المُودَعة.

## ما يحمله evidence_row (أعداد، لا θ)

يستهلك محرك حالة المهارة نتيجة تمحيص من 3 بنود لكل مهارة فرعية، لا θ. وفق قاعدة تمحيص
المهارة في v5، تُحلّ البنود الثلاثة كالتالي: `3/3 = no need` و`2/3 = monitor` و
`0-1/3 = training need`. يكتب الجسر ذلك المُدخل مباشرةً:

- `evidence_row.value = { correct, total, sourceSessionId }` مع
  `evidenceType = "screening_score"`.
- `correct` مجموع من `inputResponses.isCorrect` **المُصحَّحة على الخادم** عبر البنود
  المُسجَّلة المتميزة. وهو **لا يُشتقّ أبداً من θ**، لأن مسار تسجيل ثانياً سيكون خطراً على
  V-6.
- `studentId = StudentProfile.id` من البداية للنهاية.
- النِّظام الاحتياطي للحتمية هو **بوابة أول انتهاء** في `finishSession`. جدول
  `evidence_row` نفسه لا يحمل قيد UNIQUE.
- نوافذ `continuous` تُنتج **لا** دليل تمحيص. تُرجع `screeningCycleToEvidenceWindow` قيمة
  null ويُتخطَّى الجسر. دليل التمحيص يكون BOY أو MOY أو EOY فقط.

## الإسقاط الكلي (6 ألواح + GLOBAL)

تعيش `writeMacroSnapshot` في `repository/snapshot-writer.ts`، مسار الكتابة الوحيد لحالة
المهارة الذي يفرضه الـ lint. تجمع `engine/macro-rollup.ts` النقية عبر `rollupMacroTile`
أحدث إصدارات `domain_status_snapshot` المُودَعة لكل مُغذٍّ في الألواح الستة بالإضافة إلى
GLOBAL.

التجميع **الأسوأ يغلب وليس رقمياً أبداً** (FR-MDR-1). سلم الأسبقية هو Severe ثم Below ثم
Approaching ثم Partial ثم Contextual ثم Meets ثم Not_Assessed. `Not_Assessed` ليست صفراً
أبداً وليست متوسطاً أبداً. لآليات التجميع الكاملة انظر
[محرك القرار](https://docs.growamal.com/ar/how-it-works/decision-engine/).

**يُكتب صف GLOBAL الميتا** لكل طالب، مع `isMetaRow=true`. وهو التجميع الشامل عبر كل
المُغذِّيات ويستهلكه `Profile_Rules_v2` PR2-00 `DATA_INCOMPLETE`. وهو صف ميتا، لا لوحة في
لوحة المعلومات أبداً.

حقيقتان إضافيتان عن اللقطة الكلية:

- يحمل `feederStatuses` الشكل `[{domainId, domainStatus, dsmRuleRef, engineSnapshotRef}]`
  ليتمكن القارئ من النزول إلى أي النطاقات دفعت لوحاً.
- يُجمَّد `computedAt` و`occurredAt` إلى `session.finishedAt` (V-6)، فتُعيد الصفوف الكلية
  تشغيلها بايتاً ببايت.

## عقد مفتاح المعرِّف (StudentProfile.id مقابل User.id)

> **تنبيه:** جداول لقطات حالة المهارة الثلاثة، بالإضافة إلى `evidence_row` و`student_assessment_result`،
> تُفتِّح `studentId` على **StudentProfile.id**، لا على User.id. أما جداول سلسلة الخطة
> والتنبيه **اللاحقة** فتبقى على فضاء معرِّفات **User.id**. فداخل وحدة واحدة تكون قراءة
> اللقطة على StudentProfile.id بينما تكون قراءة التعيين أو التنبيه بجانبها على User.id. هذه
> أكثر حقيقة إرباكاً لأي قارئ مستقبلي: لا تفترض أن فضاءي المعرِّفات قابلان للتبادل.

أصلحت كنسة مفتاح المعرِّف كل قارئ كان يقرأ لقطة على User.id، على مستويَين:

1. مستهلكو الكلي المُسمَّون: التقارير وPDF لوحة الإدارة ومتعدد المدارس وPDF الوالد ودالة
   `readProfileInputContext` في وحدة الملف.
2. قُرَّاء لقطات خط القرار: bundle وrti وdata-room وism وworkflow. كلٌّ منها يحلّ User.id
   إلى StudentProfile.id **لقراءات لقطاته فقط**.

الحدّ (المُتتبَّع كـ Q-BRIDGE-5، مؤجَّل) هو أن جداول السلسلة
(`student_profile_assignment` و`bundle_assignment` و`bundle_recommendation` و
`student_tier_status` و`acute_regression_alert` و`student_scaffold_assignment` و
`monitoring_status_review` و`data_room_*` و`decision_packet_*`) تبقى على فضاء معرِّفات
User.id المتسق ذاتياً الذي تُمرِّره سلسلة الملف والحزمة وrti والمراقبة من البداية للنهاية.
وتطبيع فضاءات معرِّفات تلك الجداول إلى StudentProfile.id متابعة واحدة متماسكة، لا تُجزَّأ
قطعة قطعة.

كان عدم التطابق كامناً لأن اختبارات التكامل تَبذر في قاعدة بيانات لكل ملف يساوي فيها
User.id قيمة StudentProfile.id بمصادفة الزيادة التلقائية. ولا يتباعد المعرِّفان إلا حين
يُنشأ مستخدمان أو أكثر قبل الطالب. اختبار الإثبات واسع الشبكة هو
`__tests__/id-key-sweep.integration.test.ts`.

## الإلحاق الحصري والحتمية وإعادة V-6

`macro_domain_status_snapshot` و`evidence_row` صفوف `.create()` بالإلحاق الحصري، يفرضها
`lint-no-update-on-audit-tables.ts`. تمر الكتابات الكلية فقط عبر `snapshot-writer.ts`،
يفرضها `lint-sse-snapshot-single-write-path.ts`.

قيد الحتمية UNIQUE المُطبَّق هو
`@@unique([studentId, key, evidenceWindow, ruleVersion, seedVersion])`، بالإضافة إلى عمود
`evidenceWindow` جديد. القيد القديم `@@unique([studentId, key, computedAt])` لم يكن يمنع
أي تكرار، لأن `computedAt` يأخذ افتراضياً قيمة `now()` ولا يتصادم أبداً. تُجري
`writeMacroSnapshot` بحثاً `findUnique` قبل الإدراج تحت القفل الاستشاري، فيكون إعادة
التحفيز بنفس الإصدار عملية لاغية. وإعادة الانتهاء لا تكتب شيئاً جديداً.

## فارغ حتى ينتهي تشخيص

الجداول الكلية فارغة في منظمة جديدة وتبقى فارغة حتى يجري `finishSession` لتشخيص لطالب.
وحتى ذلك الحين، تُرجع سطوح التقارير ولوحة الإدارة والوالد شكل `dataIncomplete` أو
`Not_Assessed` مع HTTP 200. تفشل مُغلقةً ولا تُرجع 404 أبداً. والتقرير الذي تكون كل قيمه
`Not_Assessed` قبل أن ينتهي أي تشخيص سلوك متوقَّع، لا خلل. يرتبط هذا بسلوك
`dataIncomplete: true` القائم الموصوف في
[التقارير وPDF الوالد](https://docs.growamal.com/ar/guides/reporting-and-parent-pdf/).

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

- [التشخيص والتدرّب](https://docs.growamal.com/ar/guides/diagnostic-and-practice/): المُنتِج الذي يُنهي جلسة ويُحفِّز الجسر.
- [محرك حالة المهارة](https://docs.growamal.com/ar/guides/skill-status-engine/): مستهلك `evidence_row` ومسكن الكاتب الكلي.
- [التقارير وPDF الوالد](https://docs.growamal.com/ar/guides/reporting-and-parent-pdf/): المستهلك الكلي الذي يقرأ اللقطات.
- [محرك القرار](https://docs.growamal.com/ar/how-it-works/decision-engine/): آليات التجميع الكاملة وصف GLOBAL الميتا.
- [قاموس المصطلحات](https://docs.growamal.com/ar/glossary/): evidence_row واللقطة الكلية وصف GLOBAL الميتا وعقد مفتاح المعرِّف والتهدئة.
