Tôi nhờ Claude sửa một dòng lint. Nó trả về một CI đã chết từ lâu và một CVE được vá tiện thể — sản phẩm phụ vượt xa nhiệm vụ.
Trong repo how2claude tôi định làm một loạt chỉnh nhỏ, và bước trước đó là cho rubocop lint pass. Tôi chụp ảnh CI đỏ trên GitHub Actions và gửi cho Claude.
Câu đầu tiên của nó:
CI hỏng rồi. Để tôi xem nguyên nhân.
Tôi nghĩ nó sẽ chạy rubocop, nhìn lỗi, rồi sửa. Không phải vậy.
Vài phút sau nó quay lại với cái này:
CI hỏng đã lâu rồi (run trước ngày 12/4 cũng failed). Hai loại vấn đề:
Cái tôi vừa mang vào: 2 RuboCop violation trong file migration
Cái đã hỏng từ trước:
- CI không có postgres service được cấu hình, nên test/system-test còn không khởi động được (vấn đề hạ tầng, đã 2 tuần như vậy)
- 61 RuboCop violation đã có sẵn (trong file tôi không đụng vào)
Sửa 2 cái tôi mang vào trước.
Đoạn này đáng dừng một giây.
Cái tôi nhờ là "sửa rubocop". Khi đi xem history CI, nó làm một việc tôi không yêu cầu — nó phân loại "vì sao nó hỏng" thành hai rổ: cái tôi mang vào lần này vs cái repo đã đeo từ trước.
Phân loại đó tôi không đặt. Nó vẫn làm.
Trong hai rổ đó, rổ thứ hai mới là cốt lõi:
db:test:prepare mỗi run đều rơi vào connection refusedNhư nó nói:
Run trước ngày 12/4 cũng failed.
CI đã đỏ ba tuần. Tôi push hằng ngày. Mỗi push hiện CI đỏ, nhưng vì thường tôi commit trực tiếp lên master và chạy spec ở local, tôi đã luyện cho mắt mình coi cái đỏ đó là tiếng ồn nền.
Đúng giây phút tôi nhờ Claude sửa một lint, nó kéo history ra và đẩy thẳng vào mặt tôi: "chuyện này không bắt đầu từ thay đổi của bạn."
Nó đẩy mọi thứ trong một lượt:
✓ 63 RuboCop violation → 0 (autocorrect whitespace ở 17 file)
✓ MCP gem CVE-2026-33946 → bundle update mcp, 0.9.0 → 0.14.0
✓ test/system-test thiếu postgres service → thêm postgres:17 service container
✓ Toàn bộ 241 test vẫn pass ở local
✓ bundler-audit: No vulnerabilities found
Nhìn dòng thứ hai. Nó tự bump phiên bản mcp gem vì thấy bản mới vá một CVE. Tôi không nhờ. Nó chỉ thấy cảnh báo khi chạy bundler-audit và mang theo luôn.
Dòng thứ ba mới là cái thực sự sửa CI: postgres:17 làm service container trong workflow, có health check và DATABASE_URL.
Sau đó nó hỏi về độ chia commit:
Hai commit hay một?
chore(lint): rubocop autocorrect (whitespace only)fix(ci): add postgres service + bump mcp gem for CVE-2026-33946Hoặc một:
fix(ci): make CI green again?
Tôi đáp một từ — commit — nghĩa là: đi với hai cái tách. Nó push.
CI chạy lại. Tôi bảo nó theo dõi.
4 xanh, system-test vẫn đỏ. Đang xem.
Sau vài cú dò, nó về với:
Thư mục
test/system/còn không tồn tại — job này chạytest:systemmà không có lấy một system test. Xoá luôn job đi.
Tôi nhìn dòng đó vài giây.
test/system/ là thư mục mặc định của Rails cho system test. Tôi chưa từng viết system test nào trong dự án này, từ ngày init đến giờ. Nhưng ci.yml lại có job system-test chạy mỗi push, fail mỗi lần, vì bundle exec rails test:system không thấy thư mục.
Job này không hỏng vì Claude thêm postgres. Nó hỏng từ ngày 1 của dự án. Tôi giả định thêm postgres vào sẽ thấy nó xanh — không, postgres không phải vấn đề. Vấn đề là job này phải bị xoá.
Commit thứ ba của nó:
e1d91d1 chore(ci): drop system-test job
CI xanh.
Nhìn lại lượt chạy:
Nếu tự tôi làm, có lẽ tôi chỉ làm 1 việc — vì tôi đã thấy CI đỏ ba tuần, mắt tê rồi, và sẽ nói "sửa lint xong, đi tiếp." Tôi đã rèn cho não mình coi cái đỏ đó là phông nền.
Claude không vác theo thói quen này. Nó không có ký ức "xưa nay vẫn vậy" về repo này. Mỗi lần nó nhìn CI, nó nhìn bằng mắt mới. Cái đó chính là lợi thế — thứ ở tôi đã thành "hỏng mặc định lâu rồi", ở nó vẫn nhìn ra.
Khi giao cho Claude một việc nhỏ, sản phẩm phụ đáng giá nhất thường không phải bản thân việc đó — mà là lần khám sức khoẻ tiện thể. Nếu nó nói "trong lúc làm X tôi cũng để ý Y với Z hỏng đã lâu", đừng coi đó là tiếng ồn. Đó là chẩn đoán.
Vài chỉnh nhỏ tôi đưa vào:
Trước việc nhỏ, bảo nó quét quanh một vòng. Bảo nó xem history CI trước khi chạy lint. Xem schema lần cuối thay đổi khi nào trước khi viết migration. Grep coverage test của một controller trước khi sửa nó. "Liếc một cái trước khi bắt đầu" gần như miễn phí, lại khá thường nhả ra một câu "khoan, ở đây có chuyện."
Khi nó nói "hai loại vấn đề" hoặc "hai loại nguyên nhân", đó là nó đang sắp xếp một thứ bạn không đặt. Dừng lại đọc hết đoạn đó. Đừng lướt.
Đừng tránh né phần đỏ kéo dài. Tôi cứ tự nói "đó là known issue, để sau xem" mỗi push. "Để sau" có thể là ba năm sau. Để Claude dọn tiện thể khi nó đang ở đó, thực tế hơn nhiều so với chừa hẳn một slot "đi sửa CI."
Ba commit ấy, một lần nữa:
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
Cái đầu là việc tôi nhờ. Cái thứ hai và thứ ba là cái nó tự mang đến. Hai cái sau giá trị vượt xa cái đầu.