تصور کنید یک غلط املایی تکحرفی در پسوند یک فایل، تمام محیط عملیاتی شما را در ۴ جولای ۲۰۲۶ به لبهٔ سقوط ببرد، آن هم بعد از اینکه دو مرحلهٔ بازبینی هوشمند آن را تأیید کردهاند. این اتفاق نشان میدهد توسعهدهندگان در مواجهه با خط لولههای چندمدلی هوش مصنوعی، دچار توهمی به نام «دفاع در عمق» شدهاند.
این وضعیت شبیه به این است که دو نگهبان استخدام کنید تا در را چک کنند، اما هر دو آموزش دیدهاند که فقط به قفل نگاه کنند و متوجه نشوند دیوار کنار در کاملاً تخریب شده است. طبق گزارش توسعهدهنده، مدل Claude Opus و یک بازبین AI دیگر، خطای بستهبندی کد را نادیده گرفتند، در حالی که راهکار درست دقیقاً در فایل مجاوری با زبان انگلیسی ساده نوشته شده بود. هر دو مدل بررسیهای محلی را انجام دادند و چراغ سبز دادند.
همانطور که در تحلیل قبلی ما دربارهی امنیت مدلهای بازمتن اشاره کردیم، اعتماد مطلق به خروجی مدلها بدون لایهی تأیید خارجی خطرناک است. در دنیای مدرن، «بیلد سبز» (Green Build) نماد امنیت است، اما این مورد ثابت کرد که چراغ سبز فقط یعنی پروژه در یک محدودهٔ خاص تمیز است. اگر آن محدوده شامل زمان اجرای واقعی (Runtime) نباشد، سیگنال گمراهکننده است. اینجا بحث اشتباه بودن مدل نبود؛ هر دو مدل در محدودهٔ وظایف کوچکشان درست عمل کردند، اما در جایی که بازبینی باید متوقف میشد، متوقف نشدند.
مکانیسم شکست
به نقل از مستندات این حادثه، توسعهدهنده هنگام رفع یک مشکل تایماوت در cron، از Claude Opus خواست تا یک تابع کمکی برای تجزیه JSON را در فایلی مجزا قرار دهد تا بتوان آن را بهصورت ایزوله تست کرد. مدل نام فایل را jsonExtract.mjs گذاشت و آن را در autoPublish.js فراخوانی کرد.
در محیط محلی، Node.js اجازه داد یک فایل ماژول ES (ESM) — که شبیه به یک قطعه پازل است که فقط با قطعات مشابه خودش جفت میشود — فایلی با پسوند .mjs را وارد کند. تمام تستهای محلی پاس شدند و به همین دلیل، نویسنده و بازبین AI هر دو تغییر را صحیح اعلام کردند.
اما در محیط استقرار Vercel، مسیر متفاوتی طی شد. در حالی که Node محلی از مسیر سازگار ESM استفاده میکرد، تابع مستقر شده سعی کرد از طریق require() در CommonJS به آن دسترسی یابد. توالی اتفاقات این بود:
- محلی: واردکننده ESM ← ماژول .mjs ← موفقیت
- مستقر شده: require() در CommonJS ← ماژول .mjs ← خطای
ERR_REQUIRE_ESM
این یک خطای سینتکس یا منطقی نبود؛ بلکه یک خطای بستهبندی بود که تنها زمانی بروز کرد که پلتفرم سیستم ماژول را بازنویسی کرد. چون این خطا در لحظه فراخوانی رخ میداد، لاگهای بیلد همچنان سبز میماندند.
درزهایی که هیچکس مالک آنها نبود
هر بررسی روی این تغییر، محدودهٔ خاصی داشت. وقتی به جای «پاس/فیل»، به «محدوده» نگاه کنیم، شکافها روشن میشوند:
- node --check: محدوده سینتکس بود. فایل تجزیه شد. نتیجه: درست، اما بیفایده.
- مجموعه تست: محدوده مسیرهای کد در محیط محلی بود. نتیجه: سبز، چون تستها هرگز مرز استقرار را رد نکردند.
- بازبینی AI: محدوده صحت منطق طبق پرامپت (شرایط رقابتی، محدوده متغیرها) بود. نتیجه: همه چیز خوب بود.
- محیط استقرار: محدوده سیستم واقعی ماژولها بود. این تنها جایی بود که باگ وجود داشت.
باگ در درز بین تفکیک محلی ESM و تفکیک استقراری CJS زندگی میکرد و هیچ ابزاری این درز را در محدوده بررسی خود نداشت. برای مدیریت این نقاط کور، برخی تیمها از استراتژیهای تفکیککننده استفاده میکنند، مشابه آنچه در راهکار ایمنسازی بررسی کدهای AI در محیطهای قدیمی گیتلب مشاهده میکنیم.
شکاف «دانش غیرفعال»
نکته قابل توجه این است که معماری درست از قبل مستند شده بود. در همان پوشه، فایلی به نام cluePrompts.js داشت که در ابتدای آن صراحتاً ذکر شده بود برای جلوگیری از همین خطا، باید از CommonJS استفاده شود.
- مستندات پروژه این قرارداد را تأیید میکرد.
- الگوی درست تنها یک فایل فاصله داشت.
- مدلهای AI متن کامنتها را نادیده گرفتند تا روی منطق کد تمرکز کنند.
چون این قرارداد فقط در قالب کامنت بود، به عنوان «متن غیرفعال» تلقی شد. دانش وجود داشت اما منتقل نشد. یک انسان هم مگر اینکه بداند دنبال چه است، متوجه این نکته نمیشد.
تله بازبینیهای همبسته
بسیاری از تیمها باور دارند استفاده از یک مدل برای نوشتن و مدل دیگر برای بازبینی، افزونگی ایجاد میکند. اما وقتی هر دو مدل «نقطه کور» مشترکی داشته باشند، این یک توهم است.
در این مورد، هر دو مدل کد را بر اساس صحت منطق در محیط محلی ارزیابی کردند. افزونگی تنها زمانی پوشش را زیاد میکند که بازبینها بهطور مستقل شکست بخورند. وقتی دو بررسی محدوده مشترکی دارند، تکرار آنها فقط اعتماد به غلط را زیاد میکند، بدون اینکه ذرهای پوشش را افزایش دهد. شناسایی این توهمات در زمان کوتاه نیازمند فرآیندهای سختگیرانهتری است، مانند سیستم پنجگانه ۱۳۷Foundry برای تأیید Pull Requestهای تولید شده توسط AI که بر شناسایی سریع خطاها تمرکز دارد.
نقش تأیید قطعی (Deterministic)
تنها ابزاری که هشدار داد، GroundTruth بود؛ یک هوک محلی قطعی. نکته اینجاست که GroundTruth با هوشمندی باگ را نگرفت — در واقع «کودر»تر از LLMها بود چون اصلاً منطق کد را نمیخواند. این ابزار هیچ دیدی به محیط Vercel نداشت.
در عوض، محدوده آن بررسی تطابق ادعا با شواهد بود. وقتی توسعهدهنده ادعا کرد تستها پاس شدهاند، GroundTruth هشدار داد چون هیچ اجرای تستی در شواهد پیدا نکرد:
[warn] false test/build claim — claimed tests/build pass ("tests pass"), but a test run looks like it reported failures — double-check
زمانی که کرش محیط استقرار در ترمینال کپی شد، GroundTruth یک تسک باز کرد و آن را باز نگه داشت تا زمانی که تغییر واقعی در Node در Diff ظاهر شد. اشتباه اصلی این بود که دو مهر سبزِ مطمئن را به یک هشدار زردِ لجباز ترجیح دادند.
مسیر حل مشکل
برای رفع کرش، تابع کمکی به CommonJS تبدیل شد تا با الگوی همسایهاش مطابقت داشته باشد:
// jsonExtract.js — CommonJS on purpose, matching cluePrompts.jsfunction _firstJsonObject(text) { /* … */ }module.exports = { _firstJsonObject };
در autoPublish.js نیز وارد کردن فایل بهروز شد. این روش بعد از بازنویسی استقرار ایمن است و مشکل در یک کامیت حل شد.
گام بعدی شما
- هر قراردادی که فقط در کامنتهاست را به تست یا Lint تبدیل کنید؛ متن در کامنت، جایی است که قراردادهای خوب میروند تا مودبانه نادیده گرفته شوند.
- برای لایههای بازبینی AI، پرامپتهایی بنویسید که مدل را مجبور کند «محدوده استقرار» و «تفاوت محیط محلی و سرور» را بهطور جداگانه بررسی کند.
- به جای تکیه بر تعداد مدلها، روی ابزارهای تأیید قطعی (Deterministic) که بر اساس شواهد (Evidence) کار میکنند سرمایهگذاری کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو