تصور کنید یک کاراکتر کوچک و نادیده در یک فایل تنظیمات، یک عامل هوش مصنوعی را متقاعد کند که تسکی را به پایان رسانده است، در حالی که در واقعیت هیچ بخشی از آن اجرا نشده است. این سناریوی خطرناک، هستهٔ کشف جدید توسعهدهندهٔ spec-lane است که در یک پست فنی مفصل به اشتراک گذاشته شد. این گزارش فاش کرد که چگونه یک پیچیدگی در تجزیهٔ فایلهای YAML، منجر به یک شکست خاموش در گیتهای تأیید (Verification Gates) این ابزار شده است. این آسیبپذیری ابتدا در Issue #45 مستند شد و متعاقباً در PR #48 برطرف گردید.
بسیاری از برنامهنویسانی که از عاملهای کدنویس (AI Coding Agents) استفاده میکنند، برای جلوگیری از توهم (Hallucination) — شبیه دوستی که با اطمینان خاطرهای را اشتباه تعریف میکند — به یک «تعریف از اتمام» (Definition of Done) متکی هستند. این فرآیند معمولاً شامل نوشتن معیارهای موفقیت صریح به فرمت ماشینخوان و بررسی مجدد آنها در یک گیت تأیید است. در spec-lane، این سازوکار تضمین میکند که کارهای مربوط به پیادهسازی تا زمانی که استانداردهای پیشفرض و قابل تأیید را برآورده نکند، کامل تلقی نشود. این سیستم را میتوان شبیه به یک نگهبان دیجیتال تصور کرد که فقط در صورتی اجازه عبور کد را میدهد که با لیست مشخصی از الزامات مطابقت داشته باشد.
همانطور که در تحلیلهای قبلی ما دربارهٔ امنیت مدلهای بازمتن اشاره کردیم، مرز بین آنچه انسان در یک فایل میخواند و آنچه ماشین تفسیر میکند، میتواند بهشدت لغزنده و خطرناک باشد. این موضوع یادآور چالشهای مشابه در شناسایی دقیق مدلهاست، جایی که عدم تطابق شناسهی مدل با خروجی میتواند شکافی خطرناک در حاکمیت و کنترل هوش مصنوعی ایجاد کند. در این مورد خاص، ابزار از یک تجزیهکننده (Parser) YAML استفاده میکرد که هر متنی بعد از علامت # در یک رشتهٔ بدون کوتیشن را بهعنوان کامنت (توضیحات) تفسیر میکرد. به نقل از مستندات فنی این پروژه، این یعنی دستورات حیاتی که برای هوش مصنوعی نوشته شده بود، پیش از آنکه هرگز به منطق تأیید برسند، بهسادگی از دادهها حذف میشدند.
مکانیسم شکست خاموش
این شکست بر روی یک معیار موفقیت خاص متمرکز بود که در Issue #45 گزارش شد: success: - ledger has exactly one PhaseGate row # include the negative case too. چون این عبارت یک «اسکالار ساده» (Plain Scalar) یا همان رشته بدون کوتیشن بود، کتابخانهٔ [email protected] آن را تقریباً به این صورت تجزیه کرد:{ "success": [ "ledger has exactly one PhaseGate row" ] }
این اتفاق باعث ایجاد یک تضاد یا شکاف بین متن منبع و مقدار تجزیهشده شد:
- متن منبع:
ledger has exactly one PhaseGate row # include the negative case too - مقدار تجزیهشده:
ledger has exactly one PhaseGate row
متن بعد از علامت # بهطور فیزیکی در فایل YAML حضور داشت، اما توسط تجزیهکننده بهعنوان کامنت شناسایی شد و از مقدار جاوااسکریپتی که توسط تابع yaml.parse() برگردانده میشد، حذف گردید.
رخنه در گیت تأیید
در ساختار spec-lane، معیارهای موفقیت و ماتریس تأیید ورودیهای جداگانهای هستند. معیار موفقیت در فایل intent.yaml قرار دارد، در حالی که رکورد تأیید مربوطه در فایل verification.yaml ذخیره میشود.
در مورد بازتولید این باگ، ماتریس تأیید از همان فرم کوتاه شده و ناقص استفاده میکرد:
- معیار:
ledger has exactly one PhaseGate row - پوشش داده شده توسط:
test - شواهد:
test/ledger.test.ts::records PhaseGate - تست نفی (Negation test):
no PhaseGate row fails
از آنجایی که ماتریس از پیش از رشتهٔ کوتاه شده استفاده میکرد، گیت تأیید دو مقدار یکسان (که هر دو کوتاه شده بودند) را با هم مقایسه کرد. در اینجا نکته کلیدی این است که گیت تأیید متنی را حذف نکرد؛ بلکه متن در مرز بین منبع YAML و مقدار تجزیهشده JS از پیش ناپدید شده بود. در نتیجه، گیت کد موفقیت 0 را برگرداند و سیستم تصور کرد تمام الزامات برآورده شده است.
شکاف بین طرحواره و منبع
توسعهدهنده اشاره کرد که اعتبارسنج طرحواره (Schema Validator) سیستم نتوانست این خطا را شناسایی کند. طرحواره برای این بخش بهطور عمدی ساده طراحی شده بود: success: z.array(z.string()).min(1). از آنجایی که نتیجهٔ کوتاه شده همچنان یک رشتهٔ کاملاً معتبر بود، بهراحتی از بررسی طرحواره عبور کرد.
این موضوع یک تمایز حیاتی در توسعهٔ عاملمحور را آشکار میکند: اینکه یک مقدار «شکل» درست داشته باشد (Schema-valid باشد)، به این معنا نیست که قصد اولیه انسان حفظ شده است. توسعهدهنده سه ادعای اشتباه را شناسایی کرد که اغلب در این سیستمها با هم خلط میشوند:
- داشتن شکل درست $\neq$ حفظ عبارت اصلی در منبع.
- حفظ شدن رشته $\neq$ نمایش درست قصد و نیت انسان.
- وجود نام یک تست در فیلد شواهد $\neq$ اجرای واقعی آن تست و اثبات ادعا.
برای بازتولید این باگ، توسعهدهنده نسخهای از CLI را از آخرین بازبینی (Revision) پیش از PR #48 ساخت. با استفاده از معیار موفقیت بدون کوتیشن و ورودی کوتاه شده در ماتریس، دستورات lane validate و lane advance --phase 4_verify هر دو با کد خروجی 0 پاس شدند. این اتفاق اجازه داد پروژه با وجود فقدان یک الزام حیاتی، از فاز 3_implement به فاز 4_verify منتقل شود.
پیادهسازی اصلاحیه Fail-Closed
برای حل این مشکل، نسخهٔ spec-lane v0.11.0 اصلاحیهای را معرفی کرد که بررسی را به ابتدای خط لوله — یعنی مرز خواندن فایل intent.yaml — منتقل میکند. این تغییر در فایلهای packages/cli/src/intent-store.ts و packages/core/src/gate.ts پیادهسازی شده است.
به جای تکیه بر مقدار تجزیهشده (Parsed Value)، ابزار اکنون مراحل زیر را طی میکند:
- تحلیل AST: پیمایش درخت نحو انتزاعی (Abstract Syntax Tree) برای شناسایی اسکالارهای ساده (PLAIN) بدون کوتیشن.
- بازرسی منبع: استفاده از محدودهٔ منبع (Source Range) برای بررسی متن خام و اصلی فایل.
- تشخیص کامنت: بررسی اینکه آیا بلافاصله بعد از اسکالار، فاصله (Space) یا تب (Tab) و سپس علامت
#در همان خط آمده است یا خیر. - رد فوری: اگر چنین مقداری در معیارهای موفقیت شناسایی شود، ابزار ورودی را پیش از آنکه هرگز به گیت برسد، رد میکند.
در این پیادهسازی، توسعهدهنده بهطور عمدی از تکیه صرف به ویژگی .comment در گرههای AST اجتناب کرد، زیرا برخی فرمهای Anchor میتوانند کامنت را به گره اشتباهی نسبت دهند. در عوض، اطلاعات نوع AST و محدوده (Range) را با متن اصلی منبع ترکیب کرد.
این یک انتخاب طراحی «شکست-بسته» (Fail-Closed) است. ابزار ترجیح میدهد یک خطای مثبت (False Positive) گزارش کند (یعنی رد کردن یک فایل معتبر که اتفاقاً کامنت دارد) تا اینکه اجازه دهد یک حذف خاموش از گیت عبور کند. با سورس کد v0.11.0، بازتولید باگ اکنون به این صورت عمل میکند:
- اسکالار ساده + کامنت داخلی: دستورات
validateوadvanceهر دو کد خروجی 2 (رد شده) را برمیگردانند. - مقدار کامل با کوتیشن: دستورات
validateوadvanceکد خروجی 0 (پاس شده) را برمیگردانند.
مرز قصد انسانی
این بررسی زنجیرهای از مرزها را نشان داد که در جریانهای کاری هوش مصنوعی اغلب محو میشوند. توسعهدهنده کل خط لوله را به این صورت تعریف کرد:
قصد انسان (آنچه فرد سعی در دستیابی به آن دارد) $\rightarrow$ منبع مشخصات (آنچه واقعاً نوشته شده) $\rightarrow$ نمایش تجزیهشده (آنچه ابزار تفسیر کرده) $\rightarrow$ تأیید (آنچه گیت مقایسه کرده) $\rightarrow$ شواهد اجرا (آنچه واقعاً اجرا یا مشاهده شده) $\rightarrow$ پذیرش (دلیل پذیرش نتیجه).
شکست در انتقال از «منبع مشخصات» به «نمایش تجزیهشده» رخ داد. این ثابت میکند حتی اگر یک گیت تأیید بهطور سازگار عمل کند، فقط میتواند آنچه را که به آن داده شده تأیید کند. اگر دادهها هنگام تجزیه فاسد شوند، گیت در واقع در حال تأیید یک دروغ است.
محدودیتهای اصلاحیه
این اصلاحیه بهطور عمدی محدود است و ادعا نمیکند که قصد انسان را «درک» میکند. این روش یک مورد Over-detection شناخته شده دارد. برای مثال، اگر در یک سند داشته باشیم:intent: business_goal: shared text # unrelated commentsuccess: - "shared text"
حتی اگر معیار موفقیت در کوتیشن باشد و حفظ شود، بررسی فعلی ممکن است سند را رد کند، زیرا یک اسکالار سادهٔ دیگر با کامنت در فایل وجود دارد که مقدار تجزیهشدهاش با معیار موفقیت یکسان است. ابزار نمیتواند ثابت کند که این دو مورد از یک منبع معنایی یکسان میآیند. این محدودیت به جای پنهان شدن، در یک تست رگرسیون (Regression Test) حفظ شده است.
برای توسعهدهندگانی که واقعاً به علامت # در معیارهای موفقیت خود نیاز دارند، راهکار ساده است: کل رشته را در کوتیشن قرار دهند: success: - "ledger has exactly one PhaseGate row # include the negative case too". این کار باعث میشود تجزیهکننده YAML علامت را بهعنوان متن لیتِرال (Literal) در نظر بگیرد.
این حادثه هشداری است برای هر کسی که برای عاملهای هوش مصنوعی «گیت» میسازد. وقتی یک جریان کاری، عبور از گیت را بهعنوان مدرکی برای اتمام کار میپذیرد، شما باید دقیقاً بدانید چه چیزی به گیت رسیده است، آن مقدار از کجا آمده و چه تغییراتی در طول مسیر روی آن دادهها صورت گرفته است.
گام بعدی شما
- تمام رشتههای حساس در فایلهای تنظیمات YAML خود را در کوتیشن (
"یا') قرار دهید تا از تفسیر اشتباه کاراکترها جلوگیری شود. - در طراحی گیتهای تأیید، به جای تکیه بر خروجی Parser، یک لایه بازرسی متن خام (Raw Text Inspection) برای موارد حساس اضافه کنید.
- فرآیند تأیید را از حالت «تطابق رشتهای» به «تأیید مبتنی بر شواهد اجرایی» تغییر دهید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهٔ تراشههای Blackwell مراجعه کنید.




گفتگو