تصور کنید حجم کد پروژه شما در یک سال از ۱۷ هزار خط به ۱۳۴ هزار خط برسد، اما هیچکدام از هزاران ثبت تغییرات (Commit) شما معنای انسانی نداشته باشد. این کابوسِ مدیریت کد، توسعهدهنده پروژه contenox را به سمتی برد که یکی از بنیادیترین ابزارهای برنامهنویسی مدرن را کنار بگذارد.
به نقل از مستندات انتشار نسخه ۱.۰.۰ این پروژه، نویسنده ادعا کرده است که «عاملهای هوش مصنوعی، تاریخچه جزئی نسخهها را منسوخ کردهاند». او گردشکار سنتی گیت (Git commit workflow) را رها کرده است. او بهجای ارسال توالی تغییرات کوچک و تدریجی، اکنون از مدل «ریزش منبع» (Source Drop) استفاده میکند؛ یعنی در هر انتشار، کل درخت کد بهصورت یک تگ امضا شده (Signed Tag) منتشر میشود. اگرچه ۹۵۷ کامیتی که منجر به این نقطه شدهاند در یک مخزن مجزا در آدرس github.com/contenox/contenox-v0 بهصورت عمومی باقی ماندهاند، اما دیگر به عنوان روش رسمی انتشار به کار نمیروند.
برای چندین دهه، صنعت نرمافزار با هر کامیت گیت به عنوان واحدی از «قصد انسانی» برخورد کرده است. فرض ساده این بود: یک انسان تصمیمی برای تغییر میگیرد، آن را تایپ میکند و پیامی مینویسد تا توضیح دهد چرا این کار را انجام داده است. این روند یک ردپای اثباتپذیری (Provenance trail) ایجاد میکرد که در آن برچسبهای زمانی (Timestamps) مانند دفترچه خاطرات تلاشهای برنامهنویس بودند و درخواستهای ادغام (Pull Requests) به عنوان بازبینی منطق کد توسط انسان عمل میکردند. هر چهار فرضِ «قصد»، «بازبینی»، «اثباتپذیری» و «تلاش انسانی» در سال ۲۰۰۸ درست بودند. اما برای درختی از کد که توسط عاملهای هوش مصنوعی نوشته میشود، هیچیک از این فرضها در عمل دوام نمیآورند. این چالشها باعث شده تا برخی از بزرگترین پروژههای جهان، مانند هسته لینوکس، الزامات سختگیرانهای برای برچسبگذاری کدهای تولیدشده توسط AI وضع کنند تا شفافیت کدنویسی حفظ شود.
این مدل زمانی فرو میپاشد که عاملهای هوش مصنوعی اکثریت کد را بنویسند. در مورد contenox، کد تولیدی زبان Go از ۱۷,۲۶۷ خط دستنویس به ۱۳۴,۰۴۰ خط با کمک عاملها رسید. این گسترش عظیم در طول ۹۵۷ کامیت در مدت کمی بیش از یک سال رخ داد که اکثر آنها جایگذارهای بیمعنایی مانند «Checkpoint»، «Fix tests» یا «Snapshot WiP» بودند.
شکست تاریخچه عاملمحور (Agentic History)
وقتی عاملها کد را در مقیاس بالا تولید میکنند، جریان کامیتها از یک «تاریخچه» به یک «لاگ خام» تبدیل میشود. نویسنده به چندین شکست بحرانی در این محیط با حجم بالای تغییرات اشاره کرد:
- کوریِ بازبینی (Review Blindness): در یک مقطع، ۵۳۰ مسیر (Path) ثبتنشده در یک درخت کاری واحد قرار داشتند. از آنج که هیچ انسانی نمیتواند بهطور واقعبینانه یک Diff شامل ۵۳۰ فایل را بازبینی کند، فایلی که حاوی قراردادهای داخلی مخزن بود بهاشتباه حذف شد و این خطا برای چندین روز شناسایی نشد.
- از دست رفتن قصد (Loss of Intent): تصمیمات دیگر در پیامهای کامیت اتفاق نمیافتند؛ بلکه در پرامپتها، اعلانهای عامل (Agent declarations) و فایلهای سیاستگذاری (Policy files) رخ میدهند. مرز هر کامیت دیگر نشاندهنده پایان یک فکر انسانی نیست، بلکه تصادفی است و به زمانی بستگی دارد که اجرای عامل متوقف شده است. این وضعیت تضاد عمییکی با روشهای سنتی مدیریت سوابق Git در برابر مکانیسمهای هماهنگی عاملهای AI ایجاد میکند.
- نشت حریم خصوصی: برای کسانی که پروژههای مشتریان را انجام میدهند، یک جریان کامیت عمومی به یک «برگه حضور و غیاب» بسیار دقیق و غیرارادی تبدیل میشود که دقیقاً فاش میکند کار در چه ساعاتی انجام شده است.
- بازبینی معکوس: تمرکز بازبینی از تحلیل کامیتها به بررسی نتایج تغییر کرد: اینکه آیا کد Build میشود، آیا تستها پاس میشوند و آیا فایل باینری نهایی عملکرد مورد نظر را دارد یا خیر.
مکانیزم «ریزش منبع» (Source Drop)
برای حل این بحران، نویسنده مخزن عمومی را به مدل «آینه انتشار» (Release-mirror) منتقل کرد. توسعه واقعی در یک Monorepo خصوصی، در کنار بخشهای تجاری محصول انجام میشود، در حالی که مخزن عمومی contenox/contenox تنها زمانی تغییر میکند که یک نسخه (Version) منتشر شود.
هر کامیت در شاخه عمومی اکنون یک «Release vX.Y.Z» است که شامل کل درخت کد است. این کار باعث میشود Diff بین دو کامیت، در واقع Diff بین دو نسخه انتشار یافته باشد که میتوان آن را در یک جلسه کوتاه بهطور کامل خواند. این فرآیند توسط یک اسکریپت شل مدیریت میشود که مراحل زیر را طی میکند:
- استخراج (Export): از دستور
git ls-files -zاستفاده میکند تا دقیقاً آنچه گیت در درخت OSS ردیابی میکند را استخراج کند و فایلهای نادیده گرفته شده (Ignored) و خروجیهای Build را حذف کند. - پاکسازی (Sanitization): دستور
grep -rIlEرا روی یک فایل به نامprivate-patterns.txtاجرا میکند؛ اگر هرگونه نشانگر خصوصی یافت شود، اسکریپت متوقف شده و از انتشار خودداری میکند. - ثبت و تگ (Commit & Tag): تمام فایلها را اضافه کرده، با استفاده از فایل
release-notes.mdبه عنوان پیام کامیت میکند و یک تگ امضا شده ایجاد میکند که یادداشتهای انتشار در بخش Annotation آن قرار میگیرند. - تحویل (Delivery): تگ امضا شده به آینه ارسال میشود، جایی که یک فایل
release.ymlباعث فعال شدن CI میشود تا چهار فایل باینری بسازد، چکسامها (Checksums) را بنویسد و اثباتپذیری (Provenance) را تایید کند.
نگهبان انسانی (The Human Gatekeeper)
این انتقال، یک اتکای خطرناک به گیتهای مکانیکی را آشکار کرد. اولین نسخه منتشر شده حاوی فایلی به نام CONTRIBUTING.md بود که توسط یک عامل نوشته شده بود و دقیقاً همان گردشکاری را توصیف میکرد که برای پنهان کردن گردشکار استفاده شده بود! چون این فایل یکی از ۲۹ فایل در یک «ریزش» واحد بود، نویسنده پیش از آنکه دائمی شود آن را نخوانده بود. هنگامی که پروکسی ماژول Go نسخه v1.0.0 را دریافت کرد، متن غیرقابل تغییر شد، زیرا تگ زدن مجدد (Re-tagging) یک ماژول Go باعث ایجاد عدم تطابق چکسام برای تمام دستورات go get بعدی میشود.
این شکست، قانون جدیدی را ایجاد کرد: فارغ از اینکه اسکریپت چقدر کارآمد باشد، هیچ چیز تا زمانی که توسط یک انسان خوانده نشود، دائمی نمیشود. گیتهای مکانیکی — مانند Linterها، تستها و اسکنرهای امنیتی — میتوانند اعتبارنامهها (Credentials) را شناسایی کنند، اما نمیتوانند یک پاراگراف نثر صادقانه را ارزیابی کنند. برای جلوگیری از «رفلکس» ارسال وصلههای سریع (مانند v1.0.1)، مخزن عمومی اکنون از یک تقویم سختگیرانه پیروی میکند و تنها یکبار در ماه بهروز میشود.
اعتماد و اثباتپذیری
این تغییر، مدل بنیادی اعتماد در متنباز را دگرگون میکند. بهجای اعتماد به یک نشان سبز CI در هر Push، از کاربران خواسته میشود به تگهای امضا شده، دستورالعملهای ساخت (Build recipes) و چکسامها اعتماد کنند. مشارکتکنندگان دیگر یک کامیت در شاخه دریافت نمیکنند؛ بلکه اعتباری تحت عنوان «Co-authored-by» در کامیت انتشار و یک خط در یادداشتهای انتشار دریافت میکنند. در این مدل، شاخه (Branch) به عنوان مدرکی برای تغییر عمل میکند، نه وسیلهای برای تحویل آن.
این رویکرد مشابه روشی است که پروژه متنباز اندروید (AOSP) سالهاست برای انتشار ریزشهای منبع استفاده میکند. تفاوت در این است که در حالی که AOSP این کار را برای مقیاس و محرمانگی انجام میداد، contenox این کار را انجام میدهد چون کامیتهای میانیِ هوش مصنوعی دیگر حاوی اطلاعاتی نیستند که ارزش انتشار داشته باشند. اگرچه لایسنس همچنان Apache-2.0 است و تاریخچه قدیمی عمومی باقی مانده، اما این مدل شبیه به نحوه انتشار تامینکنندگان نرمافزارهای تجاری (Proprietary) است.
برای حوزه گستردهتر، این موضوع نشاندهنده یک بحران قریبالوقوع در تجربه توسعهدهنده (DX) است. نویسنده پیشنهاد میکند که گیتهاب باید یک حالت مخزن «Release Drop» پیادهسازی کند که در آن شاخه main تنها از طریق تگ جابجا شود، تاریخچه شامل یک کامیت به ازای هر نسخه باشد و Pull Requestها بهجای ادغام (Merge)، به عنوان پیشنهاد (Proposal) تلقی شوند. تا آن زمان، تنها راه حل یک اسکریپت شل، یک تقویم و یک بازبین انسانی است.
گام بعدی شما
- اگر از عاملهای کدنویس استفاده میکنید، بهجای کامیتهای ریز، روی «بازبینی خروجی نهایی» تمرکز کنید.
- برای پروژههای بزرگ، مدل Release-Mirror را جایگزین Pushهای مستقیم به Main کنید تا نویز کد ماشینی حذف شود.
- یک چکلیست انسانی برای بررسی فایلهای متنی (مانند README) قبل از تگ زدن نهایی ایجاد کنید.
اما این تغییر در متدولوژی، تنها بخشی از بحران تجربه توسعهدهنده است؛ در گزارش بعدی بررسی خواهیم کرد که چگونه GitHub باید برای عصر «کدنویسی لرزشی» (Vibe Coding) بازطراحی شود.




گفتگو