Free

طلبتُ من Claude إصلاح lint، فأخرج لي CI نصف ميّت

طلبتُ من Claude إصلاح سطر lint واحد. أعاد لي CI ميّتاً منذ أسابيع وثغرة CVE مُرَقَّعة كهديّة — النواتج الجانبيّة فاقت المهمّة نفسها.


في مستودع how2claude كنتُ على وشك إجراء جولة تعديلات صغيرة، والخطوة التمهيديّة هي تمرير rubocop lint. التقطتُ صورة لـ CI الأحمر على GitHub Actions وأرسلتها إلى Claude.

أوّل جملةٍ منه:

CI ساقط. سأذهب لأرى السبب.

ظننتُ أنّه سيُشغّل rubocop، ينظر إلى الأخطاء، ثمّ يُصلحها. لم يحدث ذلك.

بعد دقائق عاد بهذا:

CI ساقط منذ فترة (الـ run السابق في 12 أبريل أيضاً failed). نوعان من المشكلات:

ما أدخلتُه أنا للتوّ: مخالفتان لـ RuboCop في ملفّات migration

ما كان معطّلاً من قبل:

  • CI لا يضمّ postgres service مُهيّأً، فلا يقوم test/system-test أصلاً (مشكلة بنية تحتيّة، الوضع كذلك منذ أسبوعَين)
  • 61 مخالفة RuboCop سابقة (في ملفّات لم ألمسها)

أبدأ بإصلاح الاثنتَين اللتَين أدخلتُهما.

تستحقّ هذه الفقرة وقفةً ثانية.

ما طلبتُه منه «أصلِح rubocop». في طريقه إلى مراجعة سجلّ CI، فعل شيئاً لم أطلبه — صنّف «لماذا هذا ساقط» في سلّتَين: ما أدخلتُه أنا هذه المرّة، وما كان المستودع يحمله من قبل.

لم أطلب هذا التصنيف. فعله بنفسه.

ثلاثة أسابيع باللون الأحمر

من السلّتَين، الثانية هي الجوهر:

  • لم يكن لـ CI workflow أيّ postgres service مُهيّأ، لذا كان db:test:prepare يقع في connection refused في كلّ run
  • ورث job الـ system-test الانهيار ذاته
  • ثمّ 61 مخالفة RuboCop متناثرة في ملفّات لم ألمسها قطّ

بكلماته:

الـ run السابق في 12 أبريل أيضاً failed.

كان CI أحمر طوال ثلاثة أسابيع. كنتُ أدفع كلّ يوم. كلّ push يُظهر CI أحمر، لكن بما أنّني عادةً أُرسل commit مباشرةً إلى master وأشغّل specs محلّيّاً، درّبتُ عيني على عَدّ هذا الأحمر ضوضاءَ خلفيّة.

في اللحظة التي طلبتُ فيها من Claude إصلاح lint واحد، استدعى السجلّ ودفع إلى وجهي عبارة «لم يبدأ هذا بتغييرك أنت».

وفي الطريق صفّى ثغرة CVE

نفّذ كلّ شيء في تمريرة واحدة:

✓ 63 مخالفة RuboCop → 0 (تصحيح تلقائيّ للمسافات في 17 ملفّاً)
✓ MCP gem CVE-2026-33946 → bundle update mcp، 0.9.0 → 0.14.0
✓ test/system-test بلا postgres service → أُضيف postgres:17 service container
✓ الـ 241 اختباراً جميعها لا تزال تنجح محلّيّاً
✓ bundler-audit: No vulnerabilities found

انظر إلى السطر الثاني. رفع نسخة mcp gem من تلقاء نفسه لأنّه رأى أنّ النسخة الجديدة تُغلق ثغرة CVE. لم أطلب. رأى التحذير ببساطة أثناء تشغيل bundler-audit فأخذه معه.

السطر الثالث هو ما أصلح CI فعلاً: postgres:17 بوصفه service container داخل الـ workflow، مع health check و DATABASE_URL.

ثمّ سأل عن دقّة تقسيم الـ commits:

commit واحد أم اثنان؟

  • chore(lint): rubocop autocorrect (whitespace only)
  • fix(ci): add postgres service + bump mcp gem for CVE-2026-33946

أم واحد: fix(ci): make CI green again؟

ردَدتُ بكلمة واحدة — commit — أي امضِ بالاثنَين منفصلَين. دفع التغييرات.

أربعة أخضر وواحد أحمر

عاد CI ليجري. طلبتُ منه أن يراقب.

أربعة أخضر، system-test ما زال أحمر. أنظر فيه.

بعد بضع تحقيقات عاد بهذا:

مجلّد test/system/ لا وجود له أصلاً — هذا الـ job يشغّل test:system بلا أيّ system test على الإطلاق. لنحذف الـ job.

بقيتُ ثوانٍ أُحدّق في هذا السطر.

test/system/ هو مجلّد Rails الافتراضيّ لاختبارات النظام. لم أكتب system test في هذا المشروع منذ أن أعطيتُه init. لكنّ ci.yml كان يحتوي system-test job يجري في كلّ push ويفشل في كلّ مرّة، لأنّ bundle exec rails test:system لم يكن يجد المجلّد.

لم يتعطّل هذا الـ job حين أضاف Claude postgres. كان متعطّلاً منذ اليوم الأوّل للمشروع. ظننتُ أنّه سيتحوّل إلى الأخضر مع postgres — لا، ليست postgres المشكلة. المشكلة أنّ هذا الـ job يجب أن يُحذَف.

الـ commit الثالث له:

e1d91d1 chore(ci): drop system-test job

CI أخضر.

النواتج الجانبيّة أثمن من المهمّة

بمراجعة هذه الجولة:

  • طلبتُ شيئاً واحداً: إصلاح rubocop
  • نفّذ فعليّاً أربعة: إصلاح lint / تصحيح ثغرة CVE في mcp / إضافة postgres service / حذف system-test job يدور في الفراغ

لو فعلتُ ذلك بنفسي لما تجاوزت الواحد — لأنّني كنتُ أرى CI أحمر طوال ثلاثة أسابيع، تخدّرت العين، وكنتُ سأقول «أصلح الـ lint وامضِ». درّبتُ عقلي على معاملة هذا الأحمر كأنّه ديكور.

Claude لا يحمل هذه العادة. لا ذاكرة لديه عن المستودع تقول «هكذا كان دوماً». في كلّ مرّة ينظر إلى CI ينظر بعين جديدة. هذا تحديداً مكمن التفوّق — ما صار عندي «معطّلاً افتراضيّاً منذ زمن»، يراه هو.

حين تُسلِّم Claude مهمّةً صغيرة، أثمن ناتجٍ جانبيّ في الغالب ليس المهمّة نفسها — بل هو الفحص الصحّيّ العَرَضيّ. إن قال لك «خلال تنفيذ X لاحظت أنّ Y و Z معطّلان منذ مدّة»، لا تَعُدَّ ذلك ضوضاء. هذا هو التشخيص.

ما أصبح عادةً لديّ

تعديلات صغيرة دخلَت سَير عملي:

قبل المهمّة الصغيرة، اطلب منه مسحاً للمحيط. لينظر إلى سجلّ CI قبل تشغيل الـ lint. ليرى متى لُمست الـ schema آخر مرّة قبل كتابة migration. ليجري grep على تغطية اختبارات controller قبل تعديله. «نظرة سريعة قبل البدء» تكلفتها شبه معدومة، وتُخرج بكثرة عبارة «انتظر، هنا شيء».

حين يقول «نوعان من المشكلات» أو «نوعان من الأسباب»، فهو يُجري ترتيباً لم تطلبه. قف واقرأ تلك الفقرة كاملةً. لا تتجاوزها.

لا تتجنّب اللون الأحمر طويل الأمد. كنتُ أقول لنفسي «هذه known issue، سأنظر فيها لاحقاً» مع كلّ push. «لاحقاً» قد تعني بعد ثلاث سنوات. أن يُنظّفها Claude في طريقه ما دام قريباً، أكثر واقعيّةً بكثير من تخصيص فترةٍ مستقلّة لـ «أُصلح CI».

الـ commits الثلاثة، مرّةً أخرى:

74a3ebf  chore(lint): rubocop autocorrect — Layout cops only
76264ee  fix(ci): add postgres service + bump mcp gem for CVE-2026-33946
e1d91d1  chore(ci): drop system-test job

الأوّل ما طلبتُه. الثاني والثالث ما جاء به من تلقاء نفسه. يفوقان قيمةً الأوّلَ بفارقٍ كبير.