> ## Documentation Index
> Fetch the complete documentation index at: https://docs.befailproof.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# التنبيهات

> توثيق تنبيهات AgentEye.

تقيّم التنبيهات قاعدة على جدول زمني وتخطرك عند تجاوز حد معين. تحول AgentEye من لوحة تحكم سلبية إلى سطح استدعاء للأمور المهمة: ارتفاع معدل الأخطاء، تراجع الكمون، انخفاض درجات المُقيّم، أو أي حدث مخصص يمكن التعبير عنه كاستعلام ClickHouse.

يغطي هذا الدليل ماهية التنبيه وأنواع المحفزات الخمسة وقنوات الإخطار الأربع ودورة حياة الحادثة والمعاملات التشغيلية.

<img src="https://mintcdn.com/exosphere/RgxYS1UZshqb4m7m/agenteye/images/alerts.png?fit=max&auto=format&n=RgxYS1UZshqb4m7m&q=85&s=52dc18ed19b4e78604c20b5608994840" alt="صفحة التنبيهات: شبكة من بطاقات قواعد التنبيهات، كل واحدة تعرض نوع المحفز ونافذة التقييم والقنوات وشارة الخطورة" width="2880" height="1800" data-path="agenteye/images/alerts.png" />

***

## المفاهيم

* **التنبيه** — القاعدة. تحدد *ماذا* يتحقق (المحفز)، *كم مرة* (فترة التقييم)، *متى تُعتبر معطلة* (منطق مركب)، *مدى الاستعجالية* (الخطورة)، و*من/أين يتم الإخطار* (القنوات).
* **الحادثة** — ما يحدث عند تفعيل التنبيه. لكل تنبيه حادثة مفتوحة واحدة على الأكثر في المرة الواحدة. التخطيات المتكررة تحدّث أدلة الحادثة نفسها. يتم حل الحوادث بواسطة المشغّل؛ الحل التلقائي عند توقف القاعدة عن التفعيل مخطط له لكنه غير مفعل حالياً.
* **القناة** — حيث يذهب الإخطار: البريد الإلكتروني أو Slack أو webhook عام أو لوحة التحكم. كل تنبيه يمكن أن يرفق أي مجموعة.

التنبيهات والحوادث تابعة لمنظمة وتُشاركها جميع مشغلو تلك المنظمة (في نشر أحادي المستأجر يكون ببساطة `default` المدمج). يمكن تعيين الحوادث إلى مشغل فردي للفحص الأولي.

***

## أنواع المحفزات

خمسة أنواع، لكل منها مواصفات JSON خاصة به. اختر الذي يطابق كيفية وصفك لـ "معطل". نموذج التنبيه الجديد في لوحة التحكم يبني نفس المواصفات لك، بتبديل محرر الشروط ليطابق نوع المحفز الذي تختاره:

<img src="https://mintcdn.com/exosphere/RgxYS1UZshqb4m7m/agenteye/images/alert-new.png?fit=max&auto=format&n=RgxYS1UZshqb4m7m&q=85&s=ee2fb0c2b98bbdc3602bb568751c5cc4" alt="نموذج التنبيه الجديد، مع الأساسيات (الاسم والوصف والتفعيل) ومنتقي المحفز يعرض عتبة المقياس و SQL المخصص ودرجة التقييم وإخفاقات التقييم والخيارات لكل حدث" width="2880" height="1800" data-path="agenteye/images/alert-new.png" />

### 1. `metric_threshold`

الأبسط. اختر مقياساً من قائمة مغلقة وعاملاً وحداً أدنى ونافذة زمنية.

| المقياس          | ما يحسبه                                                                |
| ---------------- | ----------------------------------------------------------------------- |
| `event_count`    | إجمالي الأحداث في النافذة                                               |
| `error_count`    | `event_type = 'error'` أو أي حدث فيه `error_type IS NOT NULL`           |
| `error_rate`     | `error_count / event_count` (0..1)                                      |
| `p95_latency_ms` | `quantile(0.95)(duration_ms)` عبر جميع الأحداث التي لديها `duration_ms` |
| `p99_latency_ms` | `quantile(0.99)(duration_ms)`                                           |
| `token_sum`      | `SUM(input_tokens + output_tokens)`                                     |

العوامل: `>`, `>=`, `<`, `<=`, `==` (تقبل أيضاً كـ `gt`, `gte`, `lt`, `lte`, `eq`).

مرشحات اختيارية: `environment`, `event_type`.

مثال على المواصفات:

```json theme={null}
{
  "metric": "p95_latency_ms",
  "filter": { "environment": "production" },
  "window_secs": 900,
  "op": ">",
  "value": 5000
}
```

### 2. `custom_sql`

لأي شيء لا تغطيه المقاييس المحددة مسبقاً. يمر SQL الذي يوفره المشغّل عبر نفس حارس `/queries/run` (SELECT/WITH فقط، بيان واحد، حد أقصى 10,000 صف) قبل أن يشغّله المُرسِل. وضعان:

* **وضع الصفوف** (بدون `op`/`value`): ينشّط التنبيه بمجرد أن تعود الاستعلام صفاً واحداً على الأقل.
* **وضع القيمة**: يجب أن تسمي الاستعلام عموداً واحداً بـ `metric_value`؛ يقارن المُرسِل `metric_value` في الصف الأول مقابل `value` باستخدام `op`.

```json theme={null}
{
  "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR",
  "op": ">",
  "value": 100
}
```

### 3. `evaluation_score`

يقرأ `agenteye.evaluations` ويقارن متوسط درجة مسماة عبر نافذة.

```json theme={null}
{
  "score_key": "hallucination",
  "op": ">",
  "value": 0.6,
  "window_secs": 3600,
  "min_count": 5,
  "environment": "production"
}
```

يحمي `min_count` من القيم الشاذة أحادية العينة؛ لن ينشّط المُرسِل حتى توجد تقييمات N على الأقل في النافذة.

### 4. `eval_compound`

اقبض على تراجع الجودة الذي يظهر فقط عبر *عدة* درجات مُقيّم في وقت واحد. حيث يراقب `evaluation_score` درجة مسماة واحدة، يركّب `eval_compound` عدة شروط درجة تقييم في تنبيه واحد ويجمع نتائجها بمنطق مختار؛ لذلك قاعدة واحدة يمكن أن تعبر عن "ينشّط إذا انخفضت الفائدة **أو** ارتفع الهلوسة"، "ينشّط فقط إذا انخفضت الفائدة **و** كفاءة الأداة معاً"، أو "ينشّط إذا أخفقت **2 على الأقل من** هذه الفحوصات الثلاثة".

كل شرط يقرأ متوسط درجة مسماة واحدة من `agenteye.evaluations` عبر النافذة المشتركة ويختبرها بعاملها وحدها الخاص. تُجمع النتائج البولية بعد ذلك بـ `combinator`:

| المُركّب            | المنطق | ينشّط عندما             |
| ------------------- | ------ | ----------------------- |
| `"any"`             | OR     | يخفق شرط واحد على الأقل |
| `"all"`             | AND    | يخفق كل شرط             |
| `{ "at_least": N }` | M من N | يخفق N شروط على الأقل   |

```json theme={null}
{
  "combinator": { "at_least": 2 },
  "conditions": [
    { "score_key": "hallucination", "op": ">", "value": 0.8 },
    { "score_key": "helpfulness",   "op": "<", "value": 0.6 },
    { "score_key": "tone",          "op": "<", "value": 0.5 }
  ],
  "window_secs": 3600,
  "min_count": 5,
  "environment": "production"
}
```

* `combinator`: `"any"`, `"all"`, أو `{ "at_least": N }`.
* `conditions[]`: كل `{ score_key, op, value }`، بنفس العوامل المحفزات الأخرى (`>`, `>=`, `<`, `<=`, `==`).
* `window_secs`: النظرة للخلف المشتركة المطبقة على كل شرط (افتراضي `3600`).
* `min_count`: الحد الأدنى لعدد التقييمات لكل شرط قبل أن يمكن لذلك الشرط أن يخفق؛ الشرط ذو العينات القليلة جداً في النافذة يعتبر "غير مخفق" (افتراضي `1`).
* `environment`: اختياري؛ يقيد كل شرط إلى بيئة واحدة.

يسجل الدليل في الإخطار متوسط كل شرط المرصود والحد الذي تم اختباره ضده وعدد التقييمات المرصودة وما إذا خفق؛ حتى تتمكن من رؤية بالضبط أي فحوصات انشطت.

### 5. `per_event`

لتنبيهات "أي حدث يطابق X وصل". بدون تجميع؛ ينشّط المُرسِل بمجرد أن يرى تطابقاً في نافذة النظرة للخلف.

```json theme={null}
{
  "event_type": "error",
  "lookback_secs": 60,
  "environment": "production",
  "tool_name": "bash",
  "agent_id": "caa",
  "error_type": "TimeoutError",
  "message_contains": "vertex-ai timed out"
}
```

جميع المرشحات مرتبطة بـ AND؛ أي حقل تتركه غير محدود.

| الحقل              | الغرض                                                                                                                                                                                                   |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent_id`         | قيد الأخطاء من وكيل معين (الواحد المعروض في صف `/errors`).                                                                                                                                              |
| `error_type`       | قيد فئة خطأ محددة (مثل `TimeoutError`) بدلاً من كل خطأ.                                                                                                                                                 |
| `message_contains` | تطابق سلسلة نصية غير حساس لحالة الأحرف ضد `payload.message`. مفيد للقبض على وضع فشل محدد واحد (مثل `prompt is too long`) بدون الإخطار بكل خطأ من نفس الوكيل. محدود بـ 200 حرف؛ تطابق كنص حرفي وليس نمط. |

تلميح: ضع `lookback_secs` لمطابقة تقريبية لـ `eval_interval_secs` الخاص بالتنبيه حتى لا تخطر مرتين عن نفس الحدث.

**اختصار من `/errors`:** لكل مجموعة خطأ، الصف الممثل في عرض الأخطاء (وقائمة تفاصيل حدث الجلسة لحدث خطأ) لديها زر **+ alert** يفتح `/alerts/new` مملوء مسبقاً بمحفز `per_event` مرتبط بـ `event_type` + بيئة ذلك الصف، بما في ذلك اسم مسبق من `error_type` للحمولة عند وجوده. تختار القنوات والنظرة للخلف بعد ذلك، لكن المطابق مملوء لك. يحتاج المشغّلون إلى `alerts:write` لظهور الزر.

***

## المنطق المركب (M من N)

لكل تنبيه معاملان صحيحان إضافيان بالإضافة إلى المحفز:

* `eval_window`: عدد التقييمات الأخيرة التي يتم النظر إليها (افتراضي 1)
* `min_breaches`: كم عدد هذه التي يجب أن تخفق قبل ينشّط التنبيه (افتراضي 1)

`1 من 1` (الافتراضي) هو "ينشّط عند الإخفاق الأول". `3 من 5` يعني "ينشّط عندما تكون القاعدة قد أخفقت 3 من آخر 5 تقييمات"، مفيد للإشارات المتذبذبة حيث قياس سيء واحد يكون ضجيجاً. يحافظ المُرسِل على مخزن مؤقت دائري لكل تنبيه؛ لا تضطر إلى إدارة حالة.

***

## فترة التقييم

`eval_interval_secs` يتحكم في عدد مرات تشغيل المُرسِل للقاعدة. محصورة بـ `[30, 86400]`. الإعدادات المحددة مسبقاً في لوحة التحكم: 1م / 5م / 15م / 1س. اختر فترة تطابق سرعة الإشارة الأساسية: تنبيه معدل خطأ 5 دقائق يُقيّم كل 15 ثانية يهدر المعالج؛ تنبيه لكل حدث يحتاج نظرة للخلف قصيرة أو سيسقط بصمت الأحداث بين النقرات.

***

## القنوات

كل تنبيه يمكن أن يرفق أي مجموعة من هذه الأربع. أوراق اعتماد لكل قناة (رابط Slack webhook، رابط webhook عام + سر التوقيع، المستقبلات الافتراضية للبريد) تُكوّن مرة واحدة في **`/settings`** وتُرجع بالاسم من كل تنبيه. بهذه الطريقة قناة Slack واحدة يمكن أن تخدم تنبيهات عديدة بدون تخزين كل واحدة لنسختها الخاصة من رابط webhook.

ثلاث أنواع قنوات خارجية (بريد، Slack، webhook) تُحكم أيضاً بمفتاح إيقاف تشغيل عام للمنظمة، `alerts.enabled_channels`. عندما ينشّط تنبيه معلق قناة من نوع ليس في هذه المجموعة، يتخطاها المُرسِل ويسجل صف `alert_notifications` بحالة `skipped_disabled` وهدف `<channel_disabled>` (مما يتيح لك إيقاف جميع توصيل Slack عام دون تحرير كل قاعدة). قناة لوحة التحكم مسموحة دائماً. انظر [التكوين](#configuration).

### البريد الإلكتروني

يعيد استخدام نفس نقل SMTP الذي يشحن رسائل تسجيل الدخول لمرة واحدة. تُحل المستقبلات بالترتيب:

1. تجاوز `recipients[]` لكل قناة (عندما غير فارغة).
2. إعداد `alerts.email_default_recipients` (مصفوفة من سلاسل البريد الإلكتروني).

إذا كان SMTP غير مُكوّن فالقناة لا تعمل؛ المُرسِل بعد ذلك يسجل صف `alert_notifications` بهدف `<smtp_unconfigured>` حتى يجعل سجل التدقيق سوء التكوين مرئياً.

### Slack

يرسل رسالة Block Kit إلى [رابط webhook وارد](https://api.slack.com/messaging/webhooks).

* رابط افتراضي: `alerts.slack_default_webhook` (يُعين في `/settings`).
* تجاوز لكل تنبيه: اضبط `webhook_setting_key` للقناة إلى أي مفتاح إعداد من نوع رابط آخر، مثل `alerts.slack_oncall`, `alerts.slack_costs`.

يتضمن الرأس رمز خطورة (`:rotating_light:` / `:warning:` / `:bell:`)، والرسالة تحمل زراً يربط بعمق بصفحة الحادثة.

### Webhook عام

تكامل JSON-POST لـ PagerDuty أو Opsgenie أو نقطة الإدخال الخاصة بك. شكل الجسد:

```json theme={null}
{
  "schema_version": 1,
  "event": "alert.firing",
  "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" },
  "alert":    { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" },
  "breach":   { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } }
}
```

عندما يُعين `alerts.webhook_signing_secret`، يتضمن الطلب رأس `X-AgentEye-Signature: sha256=<hex>`، HMAC-SHA256 من الجسد باستخدام السر. تحقق من جانب المستقبل قبل الوثوق بالحمولة.

يحمل الرأس `X-AgentEye-Event` `alert.firing` / `alert.test`. (`alert.resolved` محجوز لميزة الحل التلقائي المخطط لها وليس مُصدراً حالياً.)

### لوحة التحكم

بدون توصيل خارجي: التنبيه يكتب ببساطة صف `alert_notifications` يعرضه سطح صفحة الحوادث. مفيد بينما تضبط قاعدة ولا تريد إزعاج نظام خارجي، أو لتنبيهات منخفضة الاستعجالية يفحصها المشغّلون أثناء الفحص الأولي العادي.

***

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

```
firing  ──ack──▶  acknowledged
   │                    │
   └────────────────────┴───── operator resolve ───▶  resolved
```

* **firing** — فتح المُرسِل للتو الحادثة أو كشف إخفاق آخر. يُروّج إخطار الإطلاق بالضبط مرة واحدة (محكوم بطابع زمني `notified_firing_at` على الحادثة).
* **acknowledged** — ضغط المشغّل على *ack* في `/incidents/:id`. الحادثة لا تزال تُعتبر مفتوحة؛ الإخفاقات اللاحقة ستحدّث أدلتها بدون إخطار مجدد.
* **resolved** — ضغط المشغّل على *resolve*. الحل التلقائي عند توقف القاعدة عن الإخفاق مخطط له لكنه غير مفعل حالياً، لذا حادثة مفتوحة تبقى مفتوحة حتى يحلها المشغّل.

يمكن لحادثة جديدة أن تعيد الفتح على نفس التنبيه في أي وقت بعد حل السابقة.

**خط زمني النشاط.** كل إجراء على حادثة — مفتوح أو معترف به أو محل — يُسجل في سجل نشاط إلحاقي ويُعرض على خط الزمن *activity* للحادثة، كل إدخال مُسند للمشغّل الذي أداه (بالبريد الإلكتروني) أو **automated** للإجراءات التي قام بها المُرسِل بنفسه (فتح تلقائي عند إخفاق). الاعتراف مشترك: عدة مشغّلين يمكنهم الاعتراف بنفس الحادثة وكل واحد يظهر كإدخال منفصل مُسند.

تجمع صندوق **الحوادث** الواردة الحوادث المفتوحة حسب الحالة وتتيح لك التصفية حسب الخطورة والمُعيّن:

<img src="https://mintcdn.com/exosphere/RgxYS1UZshqb4m7m/agenteye/images/incidents.png?fit=max&auto=format&n=RgxYS1UZshqb4m7m&q=85&s=2ec7841f0329c15974b52a761b6dcdcc" alt="صندوق الحوادث يعرض بطاقات حوادث مرتبطة بتنبيهات وحوادث يدوية برامج خطورة ومُعيّنين" width="2880" height="1800" data-path="agenteye/images/incidents.png" />

فتح حادثة يعرض أدلة الإخفاق والمُعيّنين والمشتركين وسجل النشاط المسند وخيط تعليقات:

<img src="https://mintcdn.com/exosphere/RgxYS1UZshqb4m7m/agenteye/images/incident-detail.png?fit=max&auto=format&n=RgxYS1UZshqb4m7m&q=85&s=d49c0814049fa568eca794743ceea7e3" alt="عرض تفاصيل حادثة: التنبيه الأب وملخص الإخفاق والمُعيّنون والمشتركون وسجل النشاط المسند والمحادثة" width="2880" height="1800" data-path="agenteye/images/incident-detail.png" />

***

## الأذونات المطلوبة

تأليف *قواعد* التنبيهات والفحص الأولي للـ *حوادث* مسألتان منفصلتان بأذونات منفصلة، حتى تتمكن من منح دوران الاستدعاء وصول الحادثة بدون منحه أيضاً القدرة على إعادة كتابة القواعد.

* `alerts:read`: اعرض قواعد التنبيهات.
* `alerts:write`: أنشئ أو حرّر أو احذف قواعد التنبيهات وشغّل إخطار اختبار.
* `incidents:read`: اعرض الحوادث.
* `incidents:write`: افتح حوادث يدوية (مجانية) غير مرتبطة بتنبيه.
* `incidents:ack`: اعترف بـ الحوادث وعيّنها وعلّق عليها وحلها.

> **`alerts:ack` القديم.** المفاتيح والمشغّلون الذين مُنحوا رمز `alerts:ack` الأقدم يستمران في العمل: يُشرّفه كـ `incidents:ack` (ويضمن `incidents:read`)، لذا المشغّلون في الخدمة الحالية يحتفظون بوصولهم بدون إعادة إصدار أوراق اعتماد. أصدر منح جديد بعائلة `incidents:*`.

امنح على مفاتيح API (`POST /keys`) والمشغّلون (`PUT /users/:id`). تحجم `PermGate` في لوحة التحكم الأزرار ذات الصلة عندما تكون الأذونة مفقودة؛ ستري `// 403` بجانب الإجراء.

> **منتقي المستقبل للبريد الإلكتروني.** يسرد منتقي المستقبل في محرر التنبيهات أعضاء مؤسستك حتى تختار بالاسم. يُحمّل لأي مشغّل يحمل `alerts:read` أو `alerts:write`؛ عرض دليل فريقك لهذا الغرض **لا** يتطلب `users:read`، والمنتقي يعيد فقط عناوين بريد الأعضاء ليس سجلات المستخدمين الكاملة.

***

## التكوين

متغيرات البيئة المُستهلكة من قبل المُرسِل:

| متغير                      | الافتراضي                    | الغرض                                                                          |
| -------------------------- | ---------------------------- | ------------------------------------------------------------------------------ |
| `ALERT_WORKERS`            | `1`                          | مهام العمل لكل مثيل خادم. معظم النشريات تحتاج واحد فقط.                        |
| `ALERT_CLAIM_BATCH`        | `16`                         | أقصى تنبيهات تعالجها نقرة عامل واحدة.                                          |
| `ALERT_POLL_IDLE_SECS`     | `5`                          | نوم العامل عندما تكون الطابور فارغة.                                           |
| `ALERT_REQUEST_TIMEOUT_MS` | `15000`                      | مهلة زمنية لتقييم كل محفز.                                                     |
| `DASHBOARD_URL`            | `https://app.befailproof.ai` | الأصل المستخدم لبناء رابط السحر في الإخطارات. اضبط لمضيف لوحة التحكم الخاص بك. |

بعد فشل التقييم العابر (ClickHouse غير متاح، مهلة استعلام)، يعيد المُرسِل محاولة القاعدة مع التراجع الأسي. بمجرد أن تراكمت قاعدة **5** إخفاقات عابرة متتالية يُعاد جدولتها بفترة طبيعية بدلاً من المتابعة بالتراجع، لذا قاعدة تفشل بثبات تبقى تُقيّم. هذا الحد ثابت وليس قابلاً للضبط من قبل المشغّل.

إعدادات القناة (مُدارة من `/settings` وليس env):

* `alerts.email_default_recipients` (`email_list`): مصفوفة JSON من سلاسل البريد الإلكتروني — المستقبلات الافتراضية لقنوات البريد.
* `alerts.slack_default_webhook` (`url`): رابط Slack webhook الوارد الافتراضي.
* `alerts.webhook_default_url` (`url`): رابط webhook عام افتراضي.
* `alerts.webhook_signing_secret` (`secret`): مفتاح HMAC-SHA256. يُعاد دائماً كـ `""` في استجابة GET؛ اكتب قيمة جديدة للتدوير.
* `alerts.enabled_channels` (`channel_set`): مجموعة أنواع القنوات الخارجية على مستوى المنظمة التي يتم توصيلها عند تفعيل تنبيه؛ الافتراضي كل ثلاثة (`email`, `slack`, `webhook`). إزالة نوع هنا توقف عام هذه القناة لكل تنبيه بدون تحرير كل قاعدة. قناة لوحة التحكم تُسلّم دائماً وغير متأثرة بهذا الإعداد.

***

## تحقق من تنبيه جديد

قبل الاعتماد على تنبيه جديد:

1. احفظه مفعلاً بقناة إخطار واحد على الأقل.
2. اختر **test** في صفحة تفاصيل التنبيه وأكد أن كل وجهة مُكوّنة تتلقى الإخطار الاصطناعي.
3. بعد أول إخفاق حقيقي، أكد أن الحادثة تظهر تحت **الحوادث** وقيمتها المقاسة تطابق استعلام لوحة التحكم المطابق.

الحوادث لا تُحل تلقائياً عند توضيح حالة. يجب على المشغّل حلها من صفحة تفاصيل الحادثة.

***

## استكشاف الأخطاء

| العرض                         | السبب المحتمل                                                                                                                                                                                                                                                            |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| التنبيه لا ينشّط أبداً        | `enabled = false`، أو لا قنوات مرفقة، أو استعلام CH الأساسي يعيد 0 صف. استخدم *test* لتأكيد القنوات؛ استخدم `/queries/run` لتأكيد المقياس.                                                                                                                               |
| إخطار Slack مفقود             | `alerts.slack_default_webhook` (أو مفتاح التجاوز لكل تنبيه) غير معين: تحقق `alert_notifications.target` لصفوف `<unset:…>`؛ أو نوع `slack` معطّل عام في `alerts.enabled_channels`: تحقق من صفوف `alert_notifications` بحالة `skipped_disabled` وهدف `<channel_disabled>`. |
| Generic webhook 401           | المستقبل يتطلب توقيعاً لكن `alerts.webhook_signing_secret` غير معين. تحقق على المستقبل أن HMAC يطابق `hmac_sha256(secret, body)`.                                                                                                                                        |
| بريد "من جميع الإرسالات فشلت" | أوراق اعتماد SMTP خاطئة أو عنوان `from` مرفوض من قبل محولك. نفس السطح الذي يشحن رسائل OTP: إذا عملت تلك فنقل SMTP حسن.                                                                                                                                                   |
| تعيد الحادثة الفتح بشكل متكرر | معاملات المركب عدوانية جداً: جرّب رفع `min_breaches` أو `eval_window` حتى ارتفاعات عابرة لا تعيد فتح الحوادث التي حللتها.                                                                                                                                                |
