Free

Claude한테 lint 좀 고치라고 했더니, 반쯤 죽은 CI까지 끌어올려 줬다

Claude한테 lint 한 줄 고쳐달라고 했더니, 오래 죽어 있던 CI와 CVE까지 같이 들고 돌아왔다 — 부산물이 본 작업보다 값나간다.


how2claude 리포에서 작은 수정 묶음을 하려는데, 그 전 단계로 리포의 rubocop lint를 통과시켜야 했다. GitHub Actions의 빨간 CI 스크린샷을 찍어서 Claude한테 보냈다.

첫 줄:

CI가 깨졌네. 원인 보고 올게.

당연히 rubocop 돌리고 에러 보고 고칠 줄 알았다. 아니었다.

몇 분 뒤 이걸 보내왔다:

CI는 한참 전부터 깨져 있었음 (직전 4월 12일 run도 failed). 문제는 두 종류:

이번에 내가 끌어들인 문제: migration 파일에 RuboCop violation 2건

원래부터 깨져 있던 문제:

  • CI에 postgres service가 설정 안 돼 있어서 test/system-test가 처음부터 못 뜸 (인프라 문제, 2주 전부터 이 상태)
  • pre-existing RuboCop 위반 61건 (내가 안 건드린 파일들)

일단 내가 끌어들인 2건부터 고칠게.

이 단락에서 1초 멈출 가치가 있다.

내가 시킨 건 "rubocop 고쳐"였다. CI history 뒤져보러 간 김에, 시키지도 않은 일을 하나 했다 — "왜 깨져 있는지"를 두 카테고리로 나눴다: 이번에 내가 끌어들인 거 vs 리포가 원래부터 깨져 있던 거.

이 분류 시킨 적 없다. 알아서 했다.

3주 동안 빨갰다

두 카테고리 중 진짜 본론은 두 번째:

  • CI workflow에 postgres service 설정이 없어서 db:test:prepare가 매번 connection refused
  • system-test job도 같은 이유로 못 뜸
  • 거기에 내가 한 번도 건드린 적 없는 파일들에 RuboCop 위반 61건

요점:

직전 4월 12일 run도 failed

CI는 3주 동안 빨갰다. 매일 push하고 있었다. push할 때마다 빨간 CI를 봤다. 근데 보통 master에 직접 commit하고 spec은 로컬에서 돌리니까, 그 빨강을 배경 노이즈로 넘기는 눈이 자라 있었다.

Claude한테 lint 한 줄 고쳐달라고 하는 그 순간, history를 끌어와서 "이거 너 이번 작업으로 시작된 게 아니야"를 얼굴 앞에 들이밀었다.

가는 김에 mcp gem CVE까지 처리

그 기세로 한 번에 다 처리했다:

✓ RuboCop 위반 63 → 0 (17개 파일 whitespace 자동 수정)
✓ 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 버전이 CVE를 고친 걸 발견하고 알아서 bundle update를 돌렸다. 시킨 적 없다. bundler-audit 돌리는 김에 경고 보고, 같이 처리해서 가져왔다.

세 번째 줄이 CI를 진짜로 살린 거: workflow에 postgres:17 service container 추가, health check, DATABASE_URL 까지.

그러고 commit 단위를 물어봤다:

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 — 라고 답했다. 제안한 두 개로 나누자는 뜻. push했다.

4 초록 1 빨강

CI가 다시 돌았다. 결과 지켜봐 달라고 했다.

4개 초록, system-test만 아직 빨강. 보고 있어.

좀 뒤지더니 이걸 보내왔다:

test/system/ 디렉터리 자체가 존재 안 함 — 이 job은 test:system을 돌리는데 시스템 테스트 자체가 없음. 그냥 job을 지우자.

그 줄을 몇 초 동안 쳐다봤다.

test/system/는 Rails의 기본 system test 디렉터리다. 이 프로젝트 init한 이래로 system test를 한 번도 쓴 적이 없다. 근데 GitHub Actions ci.yml에는 system-test job이 처음부터 들어 있었고, push할 때마다 돌고, 매번 fail했다. bundle exec rails test:system이 디렉터리를 못 찾으니까.

이 job은 Claude가 postgres 추가한 다음에 깨진 게 아니다. 프로젝트가 존재한 첫날부터 깨져 있었다. postgres 추가하면 초록 될 거라 생각했다. 아니었다 — postgres가 문제가 아니었다. 문제는 이 job이 지워져야 했다는 것.

세 번째 commit:

e1d91d1 chore(ci): drop system-test job

CI 전체 초록.

Claude한테 lint 한 줄 고치게 했을 때, 부산물이 더 값지다

이번 run을 돌아보자:

  • 내가 시킨 건 1개: rubocop 고치기
  • Claude가 실제로 한 건 4개: lint 수정 / mcp CVE 패치 / postgres service 추가 / 공회전하던 system-test job 삭제

내가 직접 했으면 1개만 했을 거다 — CI 빨간 거 3주째 보고 있어서 눈이 무뎌졌고, "이번 lint만 고치고 끝내자"로 갔을 거다. 그 빨강을 "배경"으로 처리하는 습관이 들어 있었다.

Claude한테는 그 습관이 없다. 리포에 대해 "원래부터 이랬다"는 기억이 없다. CI를 볼 때마다 처음 보는 감각이다. 이게 오히려 강점 — 내가 안 보이게 된 "장기 디폴트 깨짐"을 저쪽은 본다.

Claude한테 작은 작업을 맡길 때, 가장 값나가는 부산물은 작업 자체의 완료가 아니라 가는 김에 해 주는 건강검진인 경우가 많다. 작업 진행 중에 "하는 김에 X, Y, Z도 한참 깨져 있는 거 발견했어"라고 보고하면, 잡음 처리하지 마라. 그게 진단서다.

이걸 습관으로 만들기

내가 개인적으로 채택한 작은 운영 방식:

작은 작업 시작 전에 주변 상태를 한 번 스캔하게 시켜라. lint 돌리기 전에 CI history 보게 한다. migration 쓰기 전에 schema가 마지막으로 바뀐 시점 보게 한다. controller 편집 전에 그 파일의 테스트 커버리지를 grep하게 한다. "시작 전 한 번 보기"는 비용 거의 0에 가까운데, 꽤 자주 "잠깐, 여기 뭐 있는데" 한 줄을 토해낸다.

"문제는 두 종류" 또는 "원인을 두 가지로 나누면"이라고 말하면, 그건 시키지 않은 정리를 하고 있다는 신호다. 그 요약 단락은 끝까지 읽어라. 휙 넘기지 마라.

장기 빨강을 우회하지 마라. 매번 push할 때마다 "이건 known issue니까 나중에 보자"라고 자신한테 말하고 있었다. "나중"은 3년 뒤일 수도 있다. 가까이 지나가는 김에 Claude가 청소하게 두는 게, "CI 고치는 날"을 따로 잡는 것보다 훨씬 현실적이다.

마지막으로 그 세 commit:

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

첫 번째가 내가 시킨 거. 두 번째와 세 번째는 알아서 가져온 거. 뒤의 두 개가 첫 번째보다 훨씬 값나간다.