ขอให้ Claude แก้ lint บรรทัดเดียว มันกลับมาพร้อม CI ที่ตายมานาน และ CVE ที่ปะแถมมา — ผลพลอยได้บดบังตัวงาน
ใน repo how2claude ผมจะทำชุดแก้เล็ก ๆ และขั้นเตรียมคือต้องให้ rubocop lint ผ่าน ผมแคปจอ CI สีแดงบน GitHub Actions แล้วส่งให้ Claude
ประโยคแรกของมัน:
CI พังครับ ขอไปดูสาเหตุก่อน
ผมคิดว่ามันจะรัน rubocop ดูข้อผิดพลาด แล้วซ่อม ไม่ใช่แบบนั้น
ไม่กี่นาทีต่อมา มันกลับมาด้วยข้อความนี้:
CI พังมาสักพักแล้ว (run ก่อนหน้าวันที่ 12 เมษายน ก็ failed) ปัญหามีสองประเภท:
ของที่ผมเพิ่งเอาเข้ามา: 2 RuboCop violation ในไฟล์ migration
ของที่พังอยู่ตั้งแต่ก่อนแล้ว:
- CI ไม่ได้ตั้ง postgres service ไว้ ทำให้ test/system-test เริ่มไม่ได้ตั้งแต่แรก (ปัญหา infra เป็นแบบนี้มา 2 สัปดาห์แล้ว)
- 61 RuboCop violation ที่มีอยู่เดิม (ในไฟล์ที่ผมไม่ได้แตะ)
ขอเริ่มจาก 2 อันที่ผมเอาเข้ามาก่อน
ย่อหน้านี้คุ้มที่จะหยุดสักวินาที
สิ่งที่ผมขอคือ "แก้ rubocop" ตอนไปดูประวัติ CI มันทำสิ่งที่ผมไม่ได้ขอ — มันจัดเรียง "ทำไมพัง" ออกเป็นสองตะกร้า: ของที่ผมเอาเข้ามารอบนี้ vs ของที่ repo แบกมาตั้งนานแล้ว
การจัดประเภทแบบนี้ผมไม่ได้สั่ง มันก็ทำเองอยู่ดี
ในสองตะกร้า ตะกร้าที่สองคือเรื่องหลัก:
db:test:prepare ติด connection refused ทุกรันในคำของมัน:
run ก่อนหน้าวันที่ 12 เมษายน ก็ failed
CI แดงมาสามสัปดาห์ ผม push ทุกวัน push ทุกครั้งเห็น CI แดง แต่เพราะส่วนใหญ่ผม commit ตรงเข้า master แล้วรัน spec ในเครื่อง ผมเลยฝึกตาตัวเองให้ดูสีแดงนั้นเป็นเสียงรบกวนพื้นหลัง
แล้ววินาทีที่ผมขอให้ Claude แก้ lint ตัวเดียว มันดึงประวัติออกมายัดใส่หน้าผมว่า "นี่ไม่ได้เริ่มจากการเปลี่ยนแปลงของคุณ"
มันกวาดทุกอย่างในรอบเดียว:
✓ 63 RuboCop violation → 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
ดูบรรทัดที่สอง มัน bump เวอร์ชัน mcp gem เองเพราะเห็นว่าเวอร์ชันใหม่ปิด CVE ผมไม่ได้ขอ มันแค่เห็น warning ตอนรัน bundler-audit แล้วลากติดมาด้วย
บรรทัดที่สามคือสิ่งที่ซ่อม CI ได้จริง: postgres:17 ในฐานะ service container ใน workflow พร้อม 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 ไป
CI รันใหม่ ผมให้มันคอยดูผล
4 ตัวเขียวแล้ว system-test ยังแดง กำลังดูอยู่
หลังจากสำรวจไม่กี่ครั้ง มันกลับมาว่า:
directory
test/system/ไม่มีอยู่จริง — job นี้รันtest:systemแต่ไม่มี system test สักตัว ลบ job ทิ้งเลยก็ได้
ผมจ้องบรรทัดนั้นอยู่หลายวินาที
test/system/ คือ directory ของ system test ตามค่าเริ่มต้นของ Rails ผมไม่เคยเขียน system test ในโปรเจกต์นี้สักครั้งตั้งแต่วันที่ init แต่ ci.yml มี system-test job ที่รันทุก push และ fail ทุกครั้ง เพราะ bundle exec rails test:system หา directory ไม่เจอ
job นี้ไม่ได้พังเพราะ Claude เพิ่ม postgres เข้าไป มันพังตั้งแต่วัน 1 ของโปรเจกต์ ผมเดาว่าใส่ postgres แล้วจะเขียว — เปล่า postgres ไม่ใช่ปัญหา ปัญหาคือต้องลบ job นี้ทิ้ง
commit ที่สามของมัน:
e1d91d1 chore(ci): drop system-test job
CI เขียว
มองย้อนรอบนี้:
ถ้าผมทำเอง คงทำแค่ 1 อย่าง — เพราะดู CI แดงมาสามสัปดาห์ ตาผมชาแล้ว และคงคิดว่า "ซ่อม lint แล้วไปต่อ" ผมฝึกสมองให้มองสีแดงนั้นเป็นฉาก
Claude ไม่ได้แบกนิสัยนี้มาด้วย มันไม่มีความทรงจำว่า "มันเป็นแบบนี้มาแต่ไหนแต่ไร" เกี่ยวกับ repo นี้ ทุกครั้งที่มองดู CI มันมองด้วยสายตาใหม่ และนี่แหละคือข้อได้เปรียบ — สิ่งที่สำหรับผมกลายเป็น "พังโดยปริยายมานานแล้ว" สำหรับมันยังเห็น
เวลาให้งานเล็ก ๆ Claude ทำ ผลพลอยได้ที่มีค่าที่สุดมักไม่ใช่ตัวงาน — แต่คือ การตรวจสุขภาพแถมที่ทำให้ไประหว่างทาง ถ้ามันบอกว่า "ระหว่างทำ X เห็น Y กับ Z พังมานานแล้วด้วย" อย่ามองเป็นเสียงรบกวน นั่นคือผลตรวจ
การปรับเล็ก ๆ ที่ผมเอามาใช้:
ก่อนงานเล็ก ให้มันสแกนรอบ ๆ ก่อนสักรอบ ก่อนรัน lint ให้ดูประวัติ CI ก่อนเขียน migration ให้ดูว่า schema ถูกแก้ครั้งล่าสุดเมื่อไร ก่อนแก้ controller ให้ grep ดู test coverage ของไฟล์นั้น "การชายตามองก่อนเริ่ม" ต้นทุนแทบเป็นศูนย์ และมักจะพ่น "เดี๋ยวนะ ตรงนี้มีอะไร" ออกมาบ่อย ๆ
ถ้ามันบอกว่า "ปัญหาสองประเภท" หรือ "สาเหตุสองชนิด" นั่นแปลว่ามันกำลังจัดระเบียบสิ่งที่คุณไม่ได้สั่ง หยุดอ่านย่อหน้านั้นจนจบ อย่าข้าม
อย่าหลบสีแดงระยะยาว ผมบอกตัวเองทุก push ว่า "นี่เป็น known issue ค่อยดูทีหลัง" "ทีหลัง" อาจหมายถึงอีกสามปี ปล่อยให้ 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
ตัวแรกคือสิ่งที่ผมขอ ตัวที่สองและสามคือสิ่งที่มันเอามาเอง สองตัวหลังมีค่ามากกว่าตัวแรกเยอะ