Free

Попросив Claude полагодити лінт, я отримав напівмертвий CI у подарунок

Попросив у Claude виправити один рядок лінта. Він повернувся з давно мертвим CI та попутно закритим CVE — побічні ефекти затьмарили задачу.


У репо how2claude я зібрався зробити невелику серію правок, і попередній крок — пройти rubocop lint. Я зробив скріншот червоного GitHub Actions CI і скинув Claude.

Його перша фраза:

CI впав. Зараз гляну чому.

Я думав, що він запустить rubocop, гляне на помилки і виправить. Не так.

За кілька хвилин він повернувся з ось цим:

CI лежить уже давно (попередній run від 12 квітня теж зафейлений). Два класи проблем:

Те, що я щойно притягнув: 2 порушення RuboCop у файлах міграцій

Те, що було зламане ще раніше:

  • У CI не налаштований postgres service, тож test/system-test навіть не стартують (інфра-проблема, у такому стані вже 2 тижні)
  • 61 раніше наявне порушення RuboCop (у файлах, яких я не торкався)

Спочатку лагоджу 2, які притягнув я.

На цьому абзаці варто на секунду зупинитись.

Я попросив його «полагоди rubocop». Заглянувши в історію CI, він зробив те, про що я не просив, — розклав «чому воно зламане» по двох кошиках: що я притягнув цього разу проти того, що репо вже давно тягне за собою.

Цю класифікацію я не запитував. Він її все одно зробив.

Три тижні у червоному

З двох кошиків по суті важливий другий:

  • У CI workflow не був налаштований postgres service, тож db:test:prepare щоразу падав у connection refused
  • system-test job успадковував той самий крах
  • Плюс 61 порушення RuboCop, розкидане по файлах, яких я ніколи не чіпав

Його словами:

Попередній run від 12 квітня теж зафейлений.

CI був у червоному три тижні. Я щодня пушив. Кожен push показував червоний CI, але оскільки я зазвичай комічу прямо в master і ганяю спеки локально, я натренував око сприймати цей червоний як фоновий шум.

І в ту саму секунду, коли я прошу Claude полагодити один лінт, він підтягує історію і тицяє мені в обличчя: «це не почалося з твоєї зміни».

І принагідно прикрив один CVE

Він провернув усе одним заходом:

✓ 63 порушення RuboCop → 0 (autocorrect whitespace по 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. Я не просив. Він просто побачив warning при bundler-audit і забрав це з собою.

Третій рядок — те, що справді полагодило CI: postgres:17 як service container у workflow, з health check і DATABASE_URL.

Далі він спитав про гранулярність комітів:

Два коміти чи один?

  • 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 перезапустився. Я попросив його стежити.

4 зелених, system-test ще червоний. Дивлюсь.

Після кількох спроб повернувся з:

Каталога test/system/ взагалі немає — цей job ганяє test:system, а жодного system-тесту немає. Просто видаляємо job.

Я кілька секунд дивився на цей рядок.

test/system/ — це дефолтна директорія для system-тестів у Rails. У цьому проєкті я ні разу не написав жодного system-тесту з того дня, як зробив init. А в ci.yml висів system-test job, який запускався на кожен push і щоразу падав, бо bundle exec rails test:system не знаходив каталог.

Цей job зламався не тоді, коли Claude додав postgres. Він був зламаний з першого дня проєкту. Я припускав, що з postgres він позеленіє — ні, postgres не був проблемою. Проблема була в тому, що job треба видалити.

Його третій коміт:

e1d91d1 chore(ci): drop system-test job

CI зелений.

Побічні ефекти цінніші за саму задачу

Якщо оглянутися на цей захід:

  • Я попросив 1 річ: полагодити rubocop
  • Він зробив по факту 4: полагодив лінт / закрив CVE mcp / додав postgres service / видалив джоб system-test, що крутився впусту

Якби я робив це сам, зробив би лише 1 — бо червоний CI я бачив три тижні, око затерлося, і я б сказав «полагоджу лінт — і поїхали». У мене виробилась звичка сприймати цей червоний як декорації.

У Claude такої звички немає. У нього немає пам'яті «воно завжди було таке» про цей репо. Щоразу, як він дивиться на CI, він дивиться свіжим поглядом. Саме в цьому й перевага — те, що для мене вже стало «давно зламано за замовчуванням», для нього видно.

Коли передаєш Claude маленьку задачу, найцінніший побічний продукт часто не сама задача — а попутний огляд здоров'я. Якщо він по ходу X каже «попутно помітив, що Y і Z теж давно лежать», не списуй це в шум. Це діагноз.

Що перетворилося на звичку

Кілька дрібних налаштувань, які я взяв у роботу:

Перед маленькою задачею хай спершу разок просканує околиці. Перед запуском лінта — хай гляне історію CI. Перед написанням міграції — коли востаннє змінювалася schema. Перед редагуванням контролера — хай пройде grep по покриттю тестами цього файлу. «Швидкий погляд перед стартом» коштує майже нічого, а доволі часто видає «зачекай, тут щось є».

Коли він каже «два класи проблем» або «два типи причин», це він робить ту саму впаковку, якої ти не замовляв. Пригальмуй і прочитай цей абзац цілком. Не пропускай.

Не об'їжджай довготривалий червоний. Я казав собі «це known issue, гляну пізніше» на кожному push. «Пізніше» може означати через три роки. Дати Claude прибрати це попутно, раз він поряд, набагато реалістичніше, ніж викроювати слот «йду лагодити CI».

Ті три коміти, ще раз:

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

Перший — те, про що я просив. Другий і третій — те, що він притягнув сам. Ці двоє коштують набагато більше за перший.