Free

ขอให้ Claude แก้ lint แต่ได้ CI ที่กึ่งตายติดมือกลับมา

ขอให้ 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 แบกมาตั้งนานแล้ว

การจัดประเภทแบบนี้ผมไม่ได้สั่ง มันก็ทำเองอยู่ดี

แดงมาแล้วสามสัปดาห์

ในสองตะกร้า ตะกร้าที่สองคือเรื่องหลัก:

  • workflow CI ไม่มี postgres service ให้ใช้ ทำให้ db:test:prepare ติด connection refused ทุกรัน
  • job system-test สืบทอด crash เดียวกัน
  • บวกกับ 61 RuboCop violation กระจายอยู่ในไฟล์ที่ผมไม่เคยแตะ

ในคำของมัน:

run ก่อนหน้าวันที่ 12 เมษายน ก็ failed

CI แดงมาสามสัปดาห์ ผม push ทุกวัน push ทุกครั้งเห็น CI แดง แต่เพราะส่วนใหญ่ผม commit ตรงเข้า master แล้วรัน spec ในเครื่อง ผมเลยฝึกตาตัวเองให้ดูสีแดงนั้นเป็นเสียงรบกวนพื้นหลัง

แล้ววินาทีที่ผมขอให้ Claude แก้ lint ตัวเดียว มันดึงประวัติออกมายัดใส่หน้าผมว่า "นี่ไม่ได้เริ่มจากการเปลี่ยนแปลงของคุณ"

ระหว่างทาง สอย CVE ทิ้งไปด้วย

มันกวาดทุกอย่างในรอบเดียว:

✓ 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 อย่าง: ซ่อม rubocop
  • มันทำจริง 4 อย่าง: ซ่อม lint / patch CVE ของ mcp / เพิ่ม postgres service / ลบ system-test job ที่หมุนเปล่ามาตลอด

ถ้าผมทำเอง คงทำแค่ 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

ตัวแรกคือสิ่งที่ผมขอ ตัวที่สองและสามคือสิ่งที่มันเอามาเอง สองตัวหลังมีค่ามากกว่าตัวแรกเยอะ