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

> نظرة عامة على سياسة ترحيل التغييرات إلى الإصدارات الأقدم في ClickHouse والنظام الآلي الذي يطبّقها

# نظام ترحيل التغييرات إلى الإصدارات الأقدم

تصف هذه الوثيقة سياسة ClickHouse لترحيل التغييرات إلى الإصدارات الأقدم، والنظام الآلي الذي يطبّقها.

<div id="release-model">
  ## نموذج الإصدارات
</div>

تتبع إصدارات ClickHouse النمط `YY.M.patch.build-type`، حيث يمثّل `YY` السنة بصيغة رقمين، ويمثّل `M` شهر الإصدار (من دون صفر بادئ)، ويمثّل `patch` رقم التصحيح ضمن الفرع، ويمثّل `build` رقم build متزايدًا باستمرار، ويكون `type` إما `stable` أو `lts`.

مثال: `25.3.8.23-lts` — إصدار LTS لشهر مارس 2025، مع التصحيح 8 وbuild رقم 23.

يوجد مساران للإصدار:

* تُنشر إصدارات **Stable** شهريًا تقريبًا. وتتلقى أحدث ثلاثة إصدارات مستقرة تصحيحات، ما يوفّر نحو ثلاثة أشهر من الدعم النشط لكل إصدار.
* تُنشر إصدارات **LTS (الدعم طويل الأمد)** في مارس وأغسطس من كل عام. ويجري دعم إصدارين من LTS في الوقت نفسه، لمدة لا تقل عن 12 شهرًا لكل منهما.

يُنصح المستخدمون الذين يشغّلون أعباء العمل في بيئة الإنتاج باستخدام أحدث إصدار stable أو إصدار LTS، وبالترقية سريعًا إلى إصدارات التصحيح الجديدة، لأن إصدارات التصحيح لا تتضمن تغييرات غير متوافقة.

<div id="backport-policy">
  ## سياسة النقل الرجعي
</div>

لا تُنقل كل التغييرات رجعيًا. والهدف هو الحفاظ على استقرار فروع الإصدار، لذلك يُحصر نطاق النقل الرجعي عمدًا في أضيق الحدود:

* **إصلاحات الأمان** — تُنقل رجعيًا دائمًا.
* **إصلاحات الأخطاء الحرجة** (الاستثناءات (الأخطاء المنطقية)، فقدان البيانات، النتائج غير الصحيحة، مشكلات RBAC) — تُحدَّد تلقائيًا للنقل الرجعي وفقًا للقواعد العامة للنقل الرجعي؛ ويُعرَف ذلك بالتصنيف `pr-critical-bugfix`، الذي يؤدي إلى إضافة `pr-must-backport` تلقائيًا.
* **إصلاحات الاستقرار والتراجعات** — تُنقل رجعيًا عندما تكون مخاطر التغيير منخفضة مقارنةً بمخاطر ترك الخطأ دون إصلاح؛ ويُشار إليها بالتصنيف `pr-must-backport` الذي يضيفه القائمون على الصيانة يدويًا.
* **إصلاحات الأخطاء الطفيفة التي يتوفر لها حل بديل** — لا تُنقل رجعيًا في العادة تجنبًا لزعزعة استقرار فروع الإصدار.
* **الميزات الجديدة، والتحسينات، وأعمال تحسين الأداء** — لا تُنقل رجعيًا.

يمثل التصنيف `pr-must-backport` التجاوز اليدوي الذي يستخدمه القائمون على الصيانة لتمييز طلب سحب بغرض نقله رجعيًا. أما التصنيف `pr-critical-bugfix` فيؤدي إلى إضافة `pr-must-backport` تلقائيًا بواسطة CI hook (راجع `pr_labels_and_category.py`).

**تصعيد التعارضات.** عندما يتعذر على النقل الرجعي التلقائي حل تعارضات الدمج، يجب مع ذلك إنشاء طلب سحب cherry-pick وإسناده إلى المؤلف، والشخص الذي أجرى الدمج، والمكلّفين الحاليين في طلب السحب الأصلي، حتى يتمكن شخص من حل التعارضات وإكمال النقل الرجعي.

<div id="backport-tool">
  ## أداة الترحيل الخلفي
</div>

تُطبَّق سياسة الترحيل الخلفي الموضَّحة أعلاه بواسطة الأداة المؤتمتة في `tests/ci/cherry_pick.py`. تعمل الأداة كمسار عمل GitHub Actions على البنية التحتية لـ ClickHouse، وتغطي جميع المتطلبات: اكتشاف فروع الإصدار النشطة، واختيار طلبات السحب المؤهلة للترحيل الخلفي، وتنفيذ إجراءَي `cherry-pick` والترحيل الخلفي على مرحلتين، وإدارة التعارضات، وفرض سياسة التأخير، والحفاظ على تزامن الوسوم.

الهدف على المدى الطويل هو استخلاص هذا التنفيذ في أداة بايثون مستقلة ومفتوحة المصدر يمكن للمشاريع الأخرى اعتمادها. والتصميم المستهدف هو:

* **قابلة للتهيئة** — تُعرَّف جميع معلمات السياسة (الوسوم المؤهِّلة، ونافذة التأخير، وحدود طلبات السحب الراكدة، وسلوك `rolling-out`، وما إلى ذلك) في ملف تهيئة، بحيث يمكن تكييف الأداة لتلائم متطلبات الترحيل الخلفي لأي مشروع من دون إجراء تغييرات على الشيفرة.
* **قابلة للتوزيع** — تُحزَّم كحزمة wheel لبايثون مكتفية ذاتيًا وقابلة للتثبيت من PyPI، من دون أي اعتماد على البنية التحتية لـ CI الخاصة بـ ClickHouse.
* **قابلة للبرمجة** — توفّر نموذج كائنات واضحًا لطلبات السحب، والوسوم، وفروع الإصدار، بحيث يمكن للمستخدمين بناء مسارات عمل مخصَّصة فوق المحرك الأساسي.

<div id="testing">
  ### الاختبار
</div>

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

* مجموعة قابلة للتهيئة من فروع الإصدار التي تمثل خطوط الإصدار،
* طلبات سحب تحمل توليفات مختلفة من تصنيفات backport،
* طلبات سحب الإصدار التي تحمل تصنيف `release` وتشير إلى فروع الإصدار.

يتيح ذلك للاختبارات التحقق من حلقة الأتمتة الكاملة — اكتشاف التصنيفات، وإنشاء فروع cherry-pick، ومعالجة التعارضات، وإنشاء طلبات سحب backport، ومنطق تعيين المسؤولين، وتخطي `rolling-out`، وسياسة التأخير — على مستودع حقيقي لكنه مؤقت، من دون المساس بحالة الإنتاج. كما يمكن إعادة استخدام البنية التحتية نفسها لإجراء اختبارات انحدار على تغييرات السياسة قبل نشرها.

<div id="active-release-branches">
  ## فروع الإصدار النشطة
</div>

فرع الإصدار النشط هو أي فرع لا يزال طلب السحب الخاص بإصداره المقابل (الذي يحمل التصنيف `release`) مفتوحًا على GitHub. تكتشف أتمتة النقل العكسي هذه الفروع ديناميكيًا عند كل تشغيل، لذلك لا حاجة إلى أي تغييرات في الإعدادات عند إصدار نسخة جديدة أو وصول نسخة قديمة إلى نهاية العمر.

يمكن أن يكون فرع الإصدار في حالة **قيد الطرح** (أي أن طلب سحب الإصدار الخاص به يحمل التصنيف `rolling-out`) خلال الفترة التي يجري فيها نشر إصدار جديد. ويُوقَف النقل العكسي العام مؤقتًا للفروع التي تكون في حالة قيد الطرح لتجنّب تعقيد عملية الطرح. لكن التصنيفات الخاصة بالإصدار (مثل `v25.3-must-backport`) تتجاوز ذلك وتفرض النقل العكسي حتى أثناء الطرح.

يحدّد التصنيف الخاص بالإصدار *أقدم* إصدار يجب أن يصل إليه طلب السحب: إذ يُنقَل عكسيًا إلى ذلك الإصدار **وإلى كل فرع إصدار نشط أحدث منه**، وليس إلى الإصدار المسمّى وحده. على سبيل المثال، إذا وُضع `v25.3-must-backport` على طلب سحب دُمج في فرع التطوير، فسيُنقَل عكسيًا إلى `25.3` وإلى كل فرع إصدار نشط بعده (`25.4` و`25.5` و…). وإذا وُجدت عدة تصنيفات خاصة بالإصدار، فالأدنى إصدارًا هو الذي يُعتدّ به، لأنه يشمل الإصدارات الأحدث أصلًا.

ليس من الضروري أن يكون الإصدار المسمّى نشطًا بحد ذاته. فالتصنيف الخاص بإصدار بلغ نهاية العمر (أي إصدار لا يملك طلب سحب إصدار مفتوحًا) يواصل دفع الإصلاح إلى كل إصدار نشط يليه، بحيث لا تؤدي الترقية من ذلك الإصدار إلى فقدان الإصلاح بصمت. على سبيل المثال، يظل `v25.12-must-backport` على طلب سحب ما يدفع النقل العكسي إلى `26.1` و`26.2` و… حتى بعد أن يكون `25.12` نفسه قد بلغ نهاية العمر.

<div id="implementation">
  ## التنفيذ
</div>

<div id="overview">
  ### نظرة عامة
</div>

تعمل أتمتة النقل الخلفي كل ساعة ضمن سير عمل `CherryPick` في GitHub Actions (`.github/workflows/cherry_pick.yml`)، والمُنفَّذ في `tests/ci/cherry_pick.py`. وهي تعمل عبر واجهة برمجة تطبيقات GitHub وعمليات git محلية على مشغّل `style-checker-aarch64` ذاتي الاستضافة.

تجري العملية على مرحلتين لكل زوج من (original PR، فرع الإصدار):

1. يُنشأ **cherry-pick PR** لعزل حلّ التعارضات عن هدف الدمج الفعلي. وإذا لم توجد تعارضات، يُدمج تلقائيًا.
2. يُنشأ **backport PR** على فرع الإصدار الفعلي، مع ضغط التغييرات المنتقاة في commit واحد.

<div id="labels">
  ### الوسوم
</div>

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

| التسمية                                            | التأثير                                                                                                                                                                                                                                                                               |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pr-must-backport`                                 | نقل خلفي إلى جميع فروع الإصدار النشطة (مع تخطي الفروع الموسومة بـ `rolling-out`)                                                                                                                                                                                                      |
| `pr-must-backport-force`                           | نقل خلفي إلى جميع فروع الإصدار النشطة، مع تجاهل قيود `rolling-out`                                                                                                                                                                                                                    |
| `pr-critical-bugfix`                               | يُفعِّل `pr-must-backport` تلقائيًا (عبر `AUTO_BACKPORT` في `pr_labels_and_category.py`)                                                                                                                                                                                              |
| `v{VER}-must-backport` (مثل `v25.3-must-backport`) | نقل خلفي إلى فرع الإصدار هذا **وكل فرع إصدار نشط أحدث منه** — يحدد رقم الإصدار أقدم إصدار *يجب* أن يصل إليه طلب السحب، حتى إذا كان الإصدار المشار إليه نفسه قد بلغ نهاية العمر. وعند وجود عدة وسوم من هذا النوع، تكون الأولوية لأدنى إصدار. كما يتجاوز تخطي `rolling-out` لتلك الفروع |
| `pr-backports-created`                             | يضبطه الروبوت عند إنشاء جميع طلبات السحب المطلوبة للنقل الخلفي؛ ويُزال إذا أُعيد فتح طلب سحب `cherry-pick`                                                                                                                                                                            |
| `pr-cherrypick`                                    | يُطبَّق على طلبات سحب `cherry-pick` التي ينشئها الروبوت                                                                                                                                                                                                                               |
| `pr-backport`                                      | يُطبَّق على طلبات السحب الخاصة بالنقل الخلفي التي ينشئها الروبوت                                                                                                                                                                                                                      |
| `do not test`                                      | يُطبَّق على طلبات سحب `cherry-pick` حتى لا يُشغَّل CI عليها                                                                                                                                                                                                                           |
| `rolling-out`                                      | يُضبط على **Release PR** للإشارة إلى أن فرعه قيد الطرح حاليًا؛ وتتخطاه عمليات النقل الخلفي العامة                                                                                                                                                                                     |

<div id="branch-and-pr-naming">
  ### تسمية الفروع وطلبات السحب
</div>

لكل رقم طلب سحب أصلي `N` وفرع إصدار `release/X.Y`:

* فرع `cherry-pick`: `cherrypick/release/X.Y/N`
* فرع `backport`: `backport/release/X.Y/N`
* عنوان طلب سحب `cherry-pick`: `Cherry pick #N to release/X.Y: <original title>`
* عنوان طلب سحب `backport`: `Backport #N to release/X.Y: <original title>`

<div id="step-by-step-process">
  ### العملية خطوة بخطوة
</div>

<Steps>
  <Step title="التعرّف على الإصدارات النشطة" id="discover-active-releases">
    تستعلم `BackportPRs.receive_release_prs` من GitHub عن جميع طلبات السحب المفتوحة الموسومة بالوسم `release`. وتكون مراجع `head` لهذه الطلبات هي أسماء فروع الإصدار (مثلًا `release/25.3`). ومن هذه الأسماء تستخلص مجموعة الوسوم الخاصة بالإصدار المطلوب البحث عنها: أي وسم `v{VER}-must-backport` موجود في المستودع ولا يكون إصداره أحدث من أحدث إصدار نشط. وتُدرج الوسوم الأقدم حتى عندما لا يعود إصدارها نشطًا (ويُتجاوز أي وسم أحدث من جميع الإصدارات النشطة، لأنه لا يمكن توسيعه إلى أي فرع نشط)، لذلك يظل من الممكن العثور على طلب سحب موسوم لإصدار بلغ نهاية العمر ما دام هناك إصدار أحدث لا يزال نشطًا.
  </Step>

  <Step title="اعثر على طلبات السحب التي يجب ترحيلها إلى الإصدارات الأقدم" id="find-prs-to-backport">
    يستخدم `BackportPRs.receive_prs_for_backport` واجهة برمجة تطبيقات البحث في GitHub للعثور على طلبات السحب المدمجة التي:

    * تحمل وسم backport واحدًا على الأقل (`pr-must-backport`, `pr-must-backport-force`, `pr-critical-bugfix`، أو وسمًا خاصًا بإصدار معيّن)، و
    * لا تحمل بالفعل `pr-backports-created`، و
    * دُمجت بعد أقدم تاريخ التزام جرى العثور عليه في أي فرع إصدار، و
    * جرى تحديثها خلال آخر 90 يومًا (للحفاظ على كفاءة استعلام البحث).
  </Step>

  <Step title="التعامل مع الفرع أثناء الطرح" id="rolling-out-branch-handling">
    عندما يحمل طلب سحب الإصدار الوسم `rolling-out`، فإن وسوم backport العامة (`pr-must-backport`، `pr-critical-bugfix`) تتخطّى ذلك الفرع. ويغلق البوت أي طلبات سحب `cherry-pick` أو `backport` أُنشئت سابقًا لذلك الفرع، مع تعليق توضيحي. أمّا الوسم الخاص بإصدار معيّن (مثل `v25.3-must-backport`) فيتجاوز هذا دائمًا — بالنسبة إلى الإصدار المذكور ولكل فرع إصدار نشط أحدث يمتد إليه. ويتجاوز `pr-must-backport-force` فحص `rolling-out` في جميع الفروع.
  </Step>

  <Step title={<>مرحلة `cherry-pick` (<code>ReleaseBranch.create_cherrypick</code>)</>} id="cherry-pick-stage">
    لكل زوج من (طلب السحب الأصلي، فرع الإصدار) لا يوجد له بعدُ طلب سحب `cherry-pick`:

    1. انتقل إلى فرع الإصدار وأنشئ منه **فرع backport** (`backport/release/X.Y/N`).
    2. نفّذ `git merge -s ours` على الأصل الأول لالتزام الدمج لإنشاء **قاعدة دمج** اصطناعية من دون أي تغييرات في المحتوى.
    3. أنشئ بالقوة **فرع cherry-pick** (`cherrypick/release/X.Y/N`) بحيث يشير مباشرةً إلى التزام الدمج الخاص بطلب السحب الأصلي.
    4. حاول تنفيذ `git merge --no-commit --no-ff` لدمج فرع cherry-pick في فرع backport:
       * إذا كان محدَّثًا بالفعل، فهذا يعني أن التغيير موجود أصلًا في فرع الإصدار — علِّمه كمكتمل وتجاوزه.
       * وإلا (سواء وُجدت تعارضات أم لا)، فأعِد الضبط وادفع الفرعين.
    5. أنشئ طلب سحب `cherry-pick` يستهدف `backport/release/X.Y/N` انطلاقًا من `cherrypick/release/X.Y/N`، مع الوسمين `pr-cherrypick` و`do not test`.
    6. مرِّر `pr-bugfix` أو `pr-critical-bugfix` من طلب السحب الأصلي عند الاقتضاء.
    7. لا يتم تعيين **المكلَّفين** في هذه المرحلة؛ إذ لا تتم إضافتهم إلا عند اكتشاف تعارضات.
  </Step>

  <Step title="الدمج التلقائي لطلبات سحب `cherry-pick` الخالية من التعارضات" id="auto-merge-conflict-free-cherry-pick-prs">
    إذا كان طلب سحب `cherry-pick` قابلاً للدمج (من دون تعارضات)، يدمجه البوت تلقائيًا عبر واجهة برمجة تطبيقات GitHub ثم ينتقل فورًا إلى مرحلة `backport`.
  </Step>

  <Step title={<>مرحلة `backport` (<code>ReleaseBranch.create_backport</code>)</>} id="backport-stage">
    بعد دمج طلب سحب cherry-pick:

    1. انتقل إلى فرع backport واسحب أحدث التحديثات.
    2. اعثر على قاعدة الدمج بين فرع الإصدار وفرع backport.
    3. نفّذ `git reset --soft` إلى قاعدة الدمج، مع دمج جميع التزامات cherry-pick في التزام واحد.
    4. أنشئ التزامًا مستخدمًا عنوان طلب سحب backport كرسالة.
    5. ادفع فرع backport بالقوة وافتح طلب سحب backport يستهدف فرع الإصدار الفعلي.
    6. أضف إلى طلب السحب الوسم `pr-backport` (و`pr-bugfix` / `pr-critical-bugfix` عند الاقتضاء).
    7. عيِّن طلب السحب إلى مؤلف طلب السحب الأصلي، ومن نفّذ دمجه، والمكلَّفين الحاليين (باستثناء حسابات الروبوت).
  </Step>

  <Step title="الاكتمال" id="completion">
    عندما يكتمل النقل إلى الإصدارات الأقدم لجميع فروع الإصدار الخاصة بطلب السحب الأصلي المعني، يضيف البوت `pr-backports-created` إلى طلب السحب الأصلي.
  </Step>

  <Step title="فحص مسبق" id="pre-check">
    قبل البدء بأي عمل على طلب سحب، يُشغِّل `ReleaseBranch.pre_check` الأمر `git merge-base --is-ancestor` للتحقق من أن التزام الدمج ليس قابلًا للوصول إليه بالفعل من فرع الإصدار. وإذا كان الأمر كذلك، فيُعتبر طلب السحب نُقل إلى الإصدارات الأقدم بالفعل ويتم تجاوزه.
  </Step>
</Steps>

<div id="stale-cherry-pick-pr-handling">
  ### التعامل مع طلبات السحب Cherry-pick الراكدة
</div>

تعمل الفئة `CherryPickPRs` في بداية كل تشغيلٍ يُنفَّذ كل ساعة، وتتعامل مع حالتين:

* **طلبات السحب cherry-pick اليتيمة**: إذا لم يعد لفرع الإصدار الخاص بطلب سحب cherry-pick طلب سحب إصدار مفتوح (أي إن الإصدار أُغلق)، فسيُغلَق طلب السحب cherry-pick تلقائيًا.
* **طلبات السحب cherry-pick المعاد فتحها**: إذا كان طلب السحب الأصلي يحمل بالفعل الوسم `pr-backports-created`، لكن طلب سحب cherry-pick الخاص به لا يزال مفتوحًا، فسيُزال الوسم `pr-backports-created` من طلب السحب الأصلي لكي يمكن إعادة معالجته.

بالنسبة إلى طلبات السحب cherry-pick التي تنتظر حل التعارضات يدويًا:

* بعد **3 أيام** من دون أي تحديثات، ينشر الروبوت تعليق تذكير مع الإشارة إلى المُسنَد إليهم.
* بعد **7 أيام** من دون أي تحديثات، ينشر الروبوت تعليق إغلاق ويغلق طلب السحب.

<div id="conflict-resolution">
  ### حل التعارضات
</div>

عندما تتسبب عملية `cherry-pick` في تعارضات، يُترك طلب السحب الخاص بـ `cherry-pick` مفتوحًا لكي يعالجها أحد الأشخاص. ويُسنِد الروبوت الطلب إلى مؤلف طلب السحب الأصلي، ومن قام بدمجه، والمُعيَّنين له. وبعد حل التعارضات ودمج طلب السحب الخاص بـ `cherry-pick`، يُنشئ الروبوت طلب سحب `backport` في التشغيل التالي المجدول كل ساعة.

للتخلّي عن `backport` بالكامل، أغلِق طلب السحب الخاص بـ `cherry-pick`. وسيتعامل الروبوت معه على أنه تم تخطيه عمدًا.

لإعادة إنشاء طلب سحب `cherry-pick` معطّل من الصفر:

1. أزِل التصنيف `pr-cherrypick` من طلب السحب الخاص بـ `cherry-pick`.
2. احذف الفرع `cherrypick/...`.
3. أزِل `pr-backports-created` من طلب السحب الأصلي إذا كان موجودًا.

<div id="ci-for-backport-prs">
  ### CI لطلبات السحب الخاصة بالترحيل العكسي
</div>

تستهدف طلبات السحب الخاصة بالترحيل العكسي فروع الإصدار، لذا فهي تستخدم سير عمل CI مخصصًا (`BackportPR`، والمُعرَّف في `ci/workflows/backport_branches.py`) بدلًا من سير عمل طلب السحب القياسي. يشغّل سير العمل هذا مجموعة فرعية ممثّلة من CI: عمليات بناء ASan/UBSan وTSan، وعمليات بناء الإصدار، وعمليات بناء macOS، والاختبارات الوظيفية تحت ASan، واختبارات الضغط تحت TSan، واختبارات التكامل. كما يتحقق من أن فرع الترحيل العكسي يحتوي على ما بين 1 و50 عملية commit، وعلى ملف واحد معدَّل على الأقل (ويُفرَض ذلك بواسطة `check_backport_branch.py`).

<div id="authentication">
  ### المصادقة
</div>

يستخدم سير العمل مفتاح SSH (`ROBOT_CLICKHOUSE_SSH_KEY`) لعمليات `git push`. وتتم المصادقة على استدعاءات واجهة برمجة تطبيقات GitHub عبر `get_best_robot_token`، التي تختار الرمز المميز صاحب أكبر حصة متبقية من مجموعة مخزّنة في SSM (`/github-tokens`). ويُستخدم `ROBOT_CLICKHOUSE_COMMIT_TOKEN` في خطوة checkout ضمن سير عمل Actions، وليس لاستدعاءات واجهة برمجة التطبيقات. وتُستبعد حسابات الروبوت (`robot-clickhouse`, `clickhouse-gh`) عند إسناد المسؤولية إلى شخص معيّن.

<div id="github-api-cache">
  ### ذاكرة التخزين المؤقت لواجهة برمجة تطبيقات GitHub
</div>

يقوم `GitHubCache` (من `cache_utils.py`) بحفظ ذاكرة التخزين المؤقت لكائن PyGithub في S3، مما يقلل من استدعاءات واجهة برمجة التطبيقات بين عمليات التشغيل كل ساعة. تُنزَّل ذاكرة التخزين المؤقت في بداية كل تشغيل وتُرفع في نهايته.

<div id="error-handling">
  ### معالجة الأخطاء
</div>

تُلتقط الأخطاء أثناء معالجة كل طلب PR على حدة وتُسجَّل، لكنها لا توقف التنفيذ. وبعد معالجة جميع طلبات PR، إذا حدثت أي أخطاء، فسيُرفَع الاستثناء `BackportException`. وفي CI، يؤدي ذلك إلى إرسال إشعار عبر `CIBuddy` إلى دردشة الفريق.
