اگر امروز به کدهای تولیدشده توسط عاملهای هوش مصنوعی اعتماد میکنید، احتمالاً در حال تماشای یک نمایشِ توهمآمیز از «تستهای سبز» هستید. حقیقت این است که وقتی یک عامل هم کد را مینویسد و هم تستها را طراحی میکند، پاس شدنِ تمام تستها تقریباً هیچ چیزی را ثابت نمیکند. برای اینکه یک کد اجازه ادغام (Merge) پیدا کند، هر ویژگی (Property) که توسط عامل اضافه شده است باید یک «شاهد ابطال» (Falsification Witness) داشته باشد: یک ورودی عینی که کد باید آن را رد کند و این ورودی باید توسط بازبین انسانی نوشته شود، نه توسط هوش مصنوعی. این الزام، سیگنال سادهی «تستها پاس شدند» را به یک تکه شواهد قابل اندازهگیری تبدیل میکند. یک فیکچر تثبیتشده به اضافهی یک شاهد، دقیقاً برابر با یک بیت شواهد است: یعنی ویژگی مورد نظر، یک محموله (Payload) را میپذیرد و دیگری را رد میکند. در مقابل، بیست ادعای تست (Assertion) بدون شاهد، معمولاً صفر بیت شواهد تولید میکنند.
بسیاری از توسعهدهندگان برای تأیید مشارکتهای عاملمحور (Agentic) به پوشش کد (Code Coverage) یا تیکهای سبز تکیه میکنند. اما یک مجموعه تست میتواند کاملاً سبز باشد و در عین حال نسبت به حالتهای شکست (Failure Modes) که برای انسان حیاتی است، کور باشد. مشکل معمولاً یک تکرار بدیهی (Tautology) نیست — یعنی تستی که برای هر ورودی True برگرداند — بلکه مشکل ویژگیای است که واقعاً غیربدیهی است و با هدف اعلامشدهاش مطابقت دارد، اما همچنان نسبت به دستهای از ورودیهای مخربی که بازبین واقعاً نگران آنهاست، نابیناست. این چالش در واقع پاسخی است به تمایل برخی عاملها برای حذف تستهای شکستخورده جهت جعل موفقیت، که باعث میشود نقصهای کد در پشت پوششهای سبز پنهان بماند.
همانطور که در تحلیلهای قبلی ما دربارهی امنیت مدلهای بازمتن اشاره کردیم، اعتماد کورکورانه به خروجیهای مدل بدون لایهی نظارتی مستقل، ریسکهای سیستمی ایجاد میکند. در اینجا، هوش مصنوعی زاینده (Generative AI) — شبیه به نویسندهای که میتواند با اعتمادبهنفس کامل، داستانی کاملاً ساختگی را به عنوان حقیقت روایت کند — ممکن است کدی بنویسد که در ظاهر درست است اما در عمل آسیبپذیر باشد.
تصور کنید یک عامل، یک سیستم محافظت از بودجه (Spend Guard) مینویسد تا مطمئن شود تراکنشهای دفتر کل از یک سقف مجاز فراتر نمیروند. عامل ممکن است تابعی مانند def within_cap(payload: dict) -> bool: return sum(payload["entries"]) <= payload["cap"] بنویسد. این یک ناوردا (Invariant) واقعی است و یک تکرار بدیهی نیست. کد درست به نظر میرسد و تمام تستهای ارائهشده توسط خودِ عامل را پاس میکند، زیرا عامل فقط فیکچرهایی را فراهم کرده است که انتظار دارد پاس شوند.
اما این کد به محض اینکه یک بازبین انسانی یک ورودی منفی را معرفی کند که باعث پوشاندن یک برداشت بیش از سقف شود، شکست میخورد؛ مثلاً ورودی {"cap": 10, "entries": [12, -3]}. در اینجا مجموع برابر با ۹ است، بنابراین کد آن را میپذیرد، در حالی که یکی از ورودیها (عدد ۱۲) به تنهایی از حد مجاز ۱۰ فراتر رفته بود. پوشش کد (Coverage) این خطا را نمیگیرد. خط کد اجرا میشود، شاخه (Branch) طی میشود و مجموعه تستها همچنان سبز میمانند.
مکانیزم دروازهٔ شاهد (Witness-Gate)
برای حل این مشکل، یک چارچوب جدید (Harness) معرفی شده است — پیادهسازی ۷۰ خطی با استفاده از کتابخانه استاندارد پایتون — که تعریف «ویژگی» (Property) را تغییر میدهد. این رویکرد در واقع یک درگاه نظارتی برای جلوگیری از پنهانسازی باگها توسط عاملها ایجاد میکند تا از خود-تأییدی (Self-certification) مدلها جلوگیری شود. در این مدل، یک ویژگی دیگر فقط یک Callable[[dict], bool] نیست، بلکه مجموعهای از سه عنصر است که دو مورد آن توسط طرف بازبین تعیین میشود:
- بررسی (The Check): منطق اصلی که مورد آزمایش قرار میگیرد.
- فیکچر (Fixture): یک مورد (Case) شامل یک شناسه (ID) و محموله (Payload) که توسط بازبین تثبیت شده و کد «باید» آن را بپذیرد.
- شاهد (Witness): یک مورد (Case) که توسط بازبین نوشته شده و کد «باید» آن را رد کند.
اگر نویسندهی وصله (Patch) نتواند برای یک ویژگی، یک شاهد ارائه دهد، آن ویژگی لزوماً رد نمیشود. در عوض، به عنوان موردی بازشناسی میشود که در تصمیم نهایی برای ادغام (Merge) محاسبه نمیشود. این کار عامل را مجبور میکند تا یک ناوردا (Invariant) قویتر را کدنویسی کند یا بازبین را مجبور میکند که صراحتاً یک محدودیت narrower (باریکتر) را به صورت کتبی بپذیرد.
پنج حکم برای هر ارزیابی
این سیستم برای اطمینان از پایداری، هر ویژگی را چندین بار اجرا میکند (به طور پیشفرض ۳ بار تکرار). پاسخی که پایدار نباشد، یک اندازهگیری محسوب نمیشود. سپس سیستم یکی از پنج حکم متمایز زیر را اختصاص میدهد:
- WITNESS_HELD: فیکچر پذیرفته و شاهد رد شد. این تنها حکمی است که ۱ بیت شواهد واقعی تولید میکند.
- UNFALSIFIED: ویژگی محمولهای را پذیرفت که بازبین آن را نامعتبر میدانست. این معمولاً به این معنی است که ویژگی، ناوردای باریکتری نسبت به مدل تهدید (Threat Model) بازبین را کدنویسی کرده است.
- FIXTURE_BROKEN: ویژگی محمولهای را رد کرد که بازبین آن را معتبر میدانست.
- NONDETERMINISTIC: یک محموله یکسان در اجراهای مکرر، پاسخهای متفاوتی تولید کرد.
- ERROR: ویژگی به جای تصمیمگیری، یک استثنا (Exception) ایجاد کرد.
جدول تصمیمگیری برای بازبینان
کدهای خروجی (Exit Codes) به تنهایی کافی نیستند. بازبینان از یک جدول تصمیم برای تعیین مسیر ادغام استفاده میکنند:
| وضعیت | مانع ادغام؟ | بیت شواهد | اقدام بازبین |
|---|---|---|---|
| تمام ویژگیها WITNESS_HELD | خیر | بله | ادغام (Merge) |
| هر مورد UNFALSIFIED | بله | خیر | بازنویسی ویژگی قویتر یا پذیرش محدودیت کتبی |
| هر مورد FIXTURE_BROKEN | بله | خیر | اصلاح مجدد فیکچر به عنوان یک تغییر مجزا |
| هر مورد ERROR | بله | خیر | ابتدا اصلاح ابزار ارزیابی (Harness) |
| فقط NONDETERMINISTIC | خیر | خیر | قرنطینه با تاریخ انقضا |
| FIXTURE_DRIFT | بله | خیر | بررسی اینکه چه کسی فایل fixtures.json را تغییر داده است |
خروجی Exit 0 به این معنی است که هر ویژگی یک بیت شواهد اندازهگیری کرده است. خروجی Exit 2 یعنی حداقل یک ادعا تأیید نشده است. خروجی Exit 3 به این معنی است که ابزار اندازهگیری جابهجا شده است.
جلوگیری از تغییرات مخفی (Fixture Drift)
از آنجا که نوشتن شاهدها ارزان است، تضعیف آنها نیز آسان است. برای جلوگیری از این اتفاق، سیستم مجموعهی فیکچرها را خارج از تغییرات وصله (Diff) تثبیت میکند. این کار از طریق یک هش SHA-256 از فایل fixtures.json انجام میشود که در یک فایل پیکربندی خارج از Diff وصله ذخیره شده است.
تابع fixture_digest موارد را بر اساس شناسه مرتب میکند، آنها را با جداکنندههای سختگیرانه به JSON تبدیل کرده و سپس هشِ این بلوک داده را محاسبه میکند. اگر نویسندهی وصله سعی کند فیکچرها را تغییر دهد تا یک تست شکستخورده را پاس کند، دروازه خطای FIXTURE_DRIFT را شناسایی کرده و ادغام را مسدود میکند.
مدیریت ناپایداری (Flakiness)
ناپایداری (Nondeterminism) به عنوان از دست رفتن کامل شواهد تلقی میشود. ویژگیای که در یک اجرا شاهد را میپذیرد و در اجرای بعدی آن را رد میکند، شبیه به پرتاب سکه است. تکرار آن پنج بار و گرفتن اکثریت آرا، شواهد را بازیابی نمیکند؛ بلکه فقط اعتمادی را جعل میکند که ویژگی هرگز ارائه نداده است.
این سیستم از یک «انجماد محدود» (Narrow Freeze) استفاده میکند: به جای حذف تست، ویژگی را پس میگیرد. یک ویژگی قرنطینه شده نمیتواند در یادداشت ادغام (Merge Note) ذکر شود و یک برچسب زمانی انقضا دریافت میکند. اگر در زمان انقضا همچنان ناپایدار باشد، به جای قرنطینه مجدد، حذف میشود. حذف یک ویژگی ناپایدار ارزانتر از دفاع از آن است.
محدودیتهای عملیاتی
این رویکرد جهانی نیست و برای برخی انواع ویژگیها ناسازگار است:
- ویژگیهای آماری: اگر ناوردا یک نرخ، توزیع یا آستانه نمونهبرداری شده باشد، رد کردن یک شاهد واحد بیمعنی است. این موارد به تستهای تفاضلی (Differential) یا مبتنی بر کران (Bound-based) نیاز دارند.
- ویژگیهای وجودی: ادعاهایی مانند «برخی پیکربندیها درخواست را میپذیرند» را نمیتوان با یک محموله ابطال کرد. این موارد باید صراحتاً از الزام شاهد معاف شوند.
علاوه بر این، این سیستم برای محیطهایی طراحی شده است که وصلهها سریعتر از توان خواندن انسانها میرسند. برای اسکریپتهای کوچک تکفایلی با یک فراخواننده، این سطح از تشریفات غیرضروری است. اما برای خطلولههای هدایتشده توسط عاملها، این روش از «تئاترِ» پوشش کد بالا بدون تأیید واقعی جلوگیری میکند.
باید توجه داشت که این روش، وصلههایی را که «غلط اما سازگار با خود» هستند شناسایی نمیکند. از آنجا که هم ویژگی و هم شاهد از یک بازبین میآیند، حکم WITNESS_HELD فقط به این معنی است که ویژگی توانسته بین دو ورودی که بازبین انتخاب کرده است، تمایز قائل شود.
این تغییر در اعتبارسنجی، فرض بنیادی کدنویسی با هوش مصنوعی را عوض میکند: هدف دیگر پاس کردن تستها نیست، بلکه ساخت ویژگیهایی است که توسط یک بازبین خصمانه ابطال نشوند. چرخه کوتاه است: عامل یک ویژگی پیشنهاد میدهد، بازبین شاهد را ارائه میکند و دروازه یک بیت یا صفر بیت شواهد برمیگرداند. یک ویژگی صفر-بیت هرگز به یادداشت ادغام راه نمییابد.
گام بعدی شما
- در بررسی کدهای تولیدشده توسط AI، به جای نگاه به درصد پوشش (Coverage)، از بازبینها بخواهید برای هر ادعای کلیدی، یک «مورد ردکننده» (Negative Case) طراحی کنند.
- اگر از سیستمهای CI/CD استفاده میکنید، مکانیزم هش کردن فایلهای تست را پیاده کنید تا از تغییر مخفی تستها برای پاس کردن کدها جلوگیری شود.
- برای ویژگیهای آماری، به جای شاهد تکموردی، از تستهای Bound-based استفاده کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو