كود المسار السعيد فقط.
يميل مساعدو الذكاء الاصطناعي إلى توليد كود يتعامل فقط مع الحالة الناجحة والسليمة — مع تخطي التحقق من صحة المدخلات، ومعالجة الأخطاء، وفحوصات القيم الفارغة/null، وحالات الحافة — بحيث يعمل الكود في العرض التوضيحي وينهار في الإنتاج الفعلي.
##العلامات والأعراض
يكتشف المراجع كود المسار السعيد فقط عندما يفترض كل سطر أن السطر السابق قد نجح: لا يتم فحص استدعاءات الشبكة لمعرفة الحالات غير الناجحة، ولا يتم تغليف JSON.parse/await res.json() في كتل معالجة، ويتم إلغاء الإشارة إلى الحقول القابلة للقيمة null مباشرة، ويتم فهرسة المصفوفات دون فحص طولها، وتتدفق المدخلات الخارجية مباشرة إلى المنطق دون أي تحقق من صحتها. عادةً ما يكون هناك مسار إرجاع واحد بالضبط ولا توجد جمل throw، ولا جمل حماية، ولا كتل catch (أو توجد كتلة catch فارغة أو تحتوي على console.log فقط).
// مولد بالذكاء الاصطناعي: سيناريو النجاح فقط هو الموجود
async function getUserCity(userId) {
const res = await fetch(`/api/users/${userId}`);
const user = await res.json();
return user.address.city.toUpperCase();
}
حالات الفشل الغائبة بصمت: لم يتم فحص res.ok (تعديل 404/500 يعيد متناً للخطأ قد يرفضه .json())، وقد يكون user عبارة عن كائن فارغ {}، وقد يكون حقل address عبارة عن null، وحقل city قد يكون undefined ← خطأ Cannot read properties of undefined. الدالة "تعمل" مقابل نموذج وهمي ناجح وتفشل أمام الواقع.
العلامات المميزة في ملف الفروقات (diff):
- دالة
asyncجديدة بدون كتلtry/catchودون استدعاء.catch()للوعد (promise). - سلاسل وصول مباشرة للخصائص (
a.b.c.d) على البيانات التي عبرت حدود الثقة/المدخلات. - استخدام غير مفحوص لـ
arr[0]، أوfind(...)!، أو تحويلات الأنواع بـas، أو تأكيدات عدم القيمة null (!) كبديل للمعالجة الحقيقية. - وجود تعليقات مثل
// TODO: handle errorsأو كتلة فارغةcatch (e) {}كعنصر نائب مؤقت. - وصف طلب السحب (PR) يقول "يعالج X" ولكن فرع نجاح X فقط هو المطبق.
##أسباب المشكلة
لماذا تنتجها النماذج؟
- احتمالية الرمز التالي تفضل التدفق النموذجي. التكملة الأكثر احتمالاً بعد
const user = await res.json()هيreturn user.something— وليس فحص حالة الاستجابة. معالجة الأخطاء هي عبارة عن كود جاهز عالي التباين يختلف من قاعدة كود لأخرى، وبالتالي فهو "مفاجئ" إحصائياً للنموذج ويتم حذفه. - بيانات التدريب منحازة للمسار السعيد. تحذف الدروس البرمجية، ولقطات ملفات README، ومقالات المدونات، وإجابات Stack Overflow المقبولة عمليات التحقق ومعالجة الأخطاء للاختصار ("تم حذف معالجة الأخطاء للتوضيح"). لقد تعلم النموذج من نصوص أزالت عمداً الكود الذي تريده أنت وتطالب به.
- التملق / مكافأة المظهر النظيف. تتم مكافأة المساعدين الذين تم ضبطهم عبر RLHF على الإجابات الموجزة والاستجابة المباشرة. يبدو الكود الدفاعي وكأنه ضوضاء، لذلك يقوم النموذج بالتحسين لإنتاج مقطع كود أنيق يبدو وكأنه يجيب على الأمر الموجه.
- غياب سياق المستودع. لا يعرف النموذج أن لديك نوع
AppError، أو مغلفResult<T>، أو مخططzod، أو اصطلاحاً لتسجيل الأخطاء، وبالتالي لا يمكنه إعادة استخدامها — ويلجأ افتراضياً إلى عدم معالجة شيء بدلاً من تخمين اصطلاحاتك. - النزعات السلوكية الموثقة. يصنف تحليل OX Security لأكثر من 300 مستودع نمط تجنب إعادة الهيكلة — ذكاء اصطناعي "يتفوق في توليد كود جديد لكنه لا يعود أبداً لتحسين البنية" — والهوس بالحلول المألوفة ضمن أهم الأنماط المضادة للذكاء الاصطناعي (تقرير OX): يصدر النموذج كوداً يعمل للمهمة الفورية ولا يعود لتقويته. ومن جهة أخرى، أظهر كود Java المولد بنماذج اللغة الكبيرة في المتوسط روائح تطبيق أكثر بنسبة 73% مقارنة بالحلول المرجعية البشرية، وكانت أكبر الزيادات في عدم الاكتمال (Incompleteness) وعدم اتساق التسمية (Inconsistent Naming Convention) والتكرار الزائد (Redundancy) (arXiv 2510.03029).
لماذا يسبب ضرراً؟
- الصحة: ينهار الكود عند مواجهة قيم
null، أو مصفوفات فارغة، أو فترات انتهاء الصلاحية، أو الاستجابات غير الناجحة (غير 200) — وهي بالضبط المدخلات التي لا تظهر في اختبار يدوي سريع. - الأمان: يثق المسار السعيد بالمدخلات بشكل ضمني. تخطي التحقق من صحة المدخلات عند الحدود هو كيفية تسلل ثغرات الحقن (injection)، واجتياز المسارات (path traversal)، وتلويث النموذج الأولي (prototype pollution). يستخدم تقرير OX عبارة "insecure by dumbness" (غير آمن بسبب الغباء) لوصف التطبيقات التي يبنيها مستخدمون غير تقنيين بالذكاء الاصطناعي وينشرونها دون خبرة أمنية — وهناك بالضبط تُشحن المسارات السعيدة غير المتحقق منها دون مراجعة (OX Security).
- عبء المراجعة وتصحيح الأخطاء: في استطلاع مطوري Stack Overflow لعام 2025، يذكر 66% من المطورين أن "حلول الذكاء الاصطناعي شبه الصحيحة ولكن ليس تماماً" هي أكبر إحباط لديهم، ويقول 45% منهم إن تصحيح الكود المولد بالذكاء الاصطناعي يستغرق وقتاً أطول. كود المسار السعيد هو النموذج المثالي لـ "شبه الصحيح" — فهو يقرأ بسلاسة ولكنه يفشل في الإنتاج الفعلي.
- تراكم الديون التقنية: نظراً لأن النموذج لا يعيد الهيكلة أو يعيد استخدام دوال الأخطاء المساعدة الحالية، فإن كل دالة مسار سعيد تمثل كتلة جديدة أحادية الاستخدام. تُظهر بيانات GitClear لعام 2025 النمط الأوسع (GitClear 2025: انخفضت الأسطر المنقولة (المعاد هيكلتها) من 25% (2021) إلى أقل من 10% (2024)، وارتفعت الأسطر المنسوخة/الملصقة من 8.3% إلى 12.3%، وتضاعفت كتل التكرار ذات الخمسة أسطر فأكثر نحو 8 مرات في 2024). ويتم تثبيت معالجة الأخطاء المفقودة لاحقاً، وتتكرر في كل موضع استدعاء، ولا تكون مركزية أبداً.
##المعالجة
تكتيكات المراجعة وصياغة الأوامر
- اجعل النموذج يعدد حالات الفشل أولاً. وجّه النموذج: "قبل كتابة الكود، عدد حالات الفشل لهذه الدالة (المدخلات السيئة، خطأ الشبكة، الاستجابات غير الناجحة، الاستجابة الفارغة/المشوهة، الحقول المفقودة، التزامن). ثم قم بتطبيق المعالجة لكل منها". إن فرض خطوة التعداد يواجه ميل الرمز التالي لتخطيها.
- أشر إلى الاصطلاحات التي يجب إعادة استخدامها. "استخدم نوع
AppError/Resultالحالي منlib/errors.tsوالمسجلloggerمنlib/log.ts؛ وتحقق من صحة الاستجابة باستخدام مخططzodفيschemas/user.ts". هذا يحول غياب المعالجة إلى إعادة استخدام بدلاً من كتلة كود مخصصة (ويتجنب الكود المكرر). - اطلب تشغيل حواجز الحماية. "شغّل
eslintوtsc --noEmitوأصلح كل تحذير، بما في ذلك@typescript-eslint/no-floating-promises". يؤدي التحقق من الأنواع مع تشغيلstrictNullChecksإلى تحويل إلغاء إشارة null الصامتة إلى أخطاء تجميع يتعين على النموذج معالجتها. - اطلب الاختبارات السلبية. اطلب اختبارات وحدة تغطي المدخلات الفارغة/الملغاة/الخاطئة، وليس فقط حالة النجاح — فغياب هذه الاختبارات هو نفسه الرائحة الفاضحة.
إعادة هيكلة الكود
أضف التحقق من الصحة عند الحدود وجمل الحماية، واجعل المعالجة مركزية. الحركات المعتمدة: جمل الحماية كما في استبدال الشرط المتداخل بعبارات الحماية (إطلاق throw مبكر عند حالة غير صالحة)، وإدخال توكيد مع التحقق عند الحدود (التنقية لا التحقق عند حواف الإدخال/الإخراج)، وإدخال كائن فارغ (قيمة حالة خاصة مثل ?? "UNKNOWN" بدلاً من الانهيار).
// بعد: حالات الفشل هي مواطنون من الدرجة الأولى
async function getUserCity(userId: string): Promise<string> {
if (!userId) throw new InvalidArgumentError("userId required"); // جملة حماية (guard clause)
const res = await fetch(`/api/users/${encodeURIComponent(userId)}`);
if (!res.ok) throw new ApiError(`user fetch failed: ${res.status}`);
const user = UserSchema.parse(await res.json()); // التحقق من الصحة عند الحدود
return user.address?.city?.toUpperCase() ?? "UNKNOWN"; // معالجة الفجوة كحالة خاصة
}
إذا بدأ نمط try/validate/log يتكرر عبر مواقع الاستدعاء، فاستخدم استخراج الدالة لنقله إلى دالة مساعدة مشتركة fetchJson<T>(url, schema) بحيث تعيش معالجة الأخطاء في مكان واحد بدلاً من نسخها ولصقها (فخ تكرار GitClear).
##أدوات الكشف
- typescript-eslint @typescript-eslint/no-floating-promises — تمييز الوعود (promises) التي لا يتم التعامل مع مسار رفضها أبداً (بدون await/catch) — وهي علامة شائعة للمسار السعيد في الاستدعاءات غير المتزامنة.
- ESLint no-empty — تمييز الكتل الفارغة بما في ذلك كتل catch الفارغة — وهي بمثابة 'معالجة الأخطاء' المؤقتة التي يتركها النموذج خلفه.
- SonarSource (JS/TS) javascript:S2486 — يجب عدم تجاهل الاستثناءات — تمييز الأخطاء التي تم التقاطها وتجاهلها بصمت، وهي الممارسة القريبة لعدم المعالجة على الإطلاق.