Claude Code cho lỗi CI: yêu cầu nó trích dẫn đầu ra lỗi, đề xuất sửa nhỏ nhất và thêm test hồi quy để ngăn lặp lại.

Một failure CI thường không bí ẩn. Log cho bạn biết chỗ dừng, lệnh nào fail và thông báo lỗi. Một lần chạy tốt sẽ có stack trace, lỗi compiler kèm file và số dòng, hoặc báo cáo test cho thấy assert nào fail. Đôi khi bạn còn có manh mối kiểu diff như "expected X, got Y" hoặc một bước fail rõ ràng như "lint", "build", hoặc "migrate database".
Vấn đề thực sự là người ta (và AI) thường xem log như tiếng ồn nền. Nếu bạn dán một log dài rồi hỏi "một sửa", nhiều model nhảy tới lời giải quen thuộc thay vì đọc những dòng có ý nghĩa cuối cùng. Việc đoán trở nên tệ hơn khi lỗi trông phổ biến ("module not found", "timeout", "permission denied"). Kết quả là một rewrite lớn, một dependency mới, hoặc câu trả lời "thử cập nhật mọi thứ" mà không ăn khớp với lỗi thật.
Mục tiêu không phải là "làm cho nó pass bằng mọi giá". Nó đơn giản hơn:
Trong thực tế, "sửa nhỏ nhất" thường là một trong các thứ sau: vài dòng code ở một chỗ, import thiếu hoặc đường dẫn sai, giá trị config rõ ràng không phù hợp với môi trường CI, hoặc hoàn tác một thay đổi vô tình phá vỡ chứ không thiết kế lại toàn bộ.
Một test theo sau cũng quan trọng. CI pass một lần không bằng ngăn lặp lại. Nếu lỗi do edge case (input null, timezone, làm tròn, quyền), thêm test hồi quy mà fail trước sửa và pass sau. Điều đó biến cứu nguy một lần thành rào chắn.
Hầu hết các sửa tồi bắt đầu từ thiếu ngữ cảnh. Nếu bạn chỉ dán dòng đỏ cuối cùng, model phải đoán chuyện xảy ra trước đó, và đoán thường thành rewrite.
Cố gắng cung cấp đủ chi tiết để ai đó có thể theo dõi lỗi từ first real error tới cuối, rồi thay đổi càng ít càng tốt.
Sao chép những thứ này vào tin của bạn (nguyên văn khi có thể):
go test ./..., npm test, flutter test, golangci-lint run).Thêm ràng buộc bằng lời thường. Nếu bạn muốn sửa nhỏ, nói rõ: không refactor, không thay đổi hành vi trừ khi cần, giữ patch giới hạn ở khu vực fail.
Một ví dụ đơn giản: CI fail ở bước lint sau khi bump dependency. Dán output lint từ cảnh báo đầu tiên, kèm lệnh CI dùng, và đề cập thay đổi phiên bản package duy nhất. Đó đủ để gợi ý một tweak config một dòng hoặc một sửa code nhỏ, thay vì reformat nửa repo.
Nếu bạn muốn thứ có thể copy-paste, cấu trúc này thường đủ:
CI command:
Failing output (full):
Recent changes:
Constraints (smallest fix, no refactor):
Flaky? (runs attached):
Khi model trượt mục tiêu trên một break CI, thường là vì prompt cho phép nó đoán. Nhiệm vụ của bạn là bắt nó cho thấy quá trình suy luận bằng chính đầu ra lỗi, rồi cam kết sửa nhỏ nhất khả dĩ.
Yêu cầu bằng chứng và một kế hoạch nhỏ. Một prompt tốt ép năm điều:
Không chắc chắn thì ổn. Không nói rõ sự không chắc chắn mới tốn thời gian.
Dán đoạn này lên đầu câu hỏi CI của bạn:
Use ONLY the evidence in the CI output below.
1) Quote the exact failing lines you are using.
2) Give ONE sentence: the most likely cause.
3) Propose the smallest fix: 1-3 edits, with file paths.
4) Do NOT do formatting/renames/refactors or "cleanup".
5) List uncertainties + the one extra detail that would confirm the diagnosis.
Nếu log nói "expected 200, got 500" kèm stack trace vào user_service.go:142, cấu trúc này đẩy phản hồi về function đó và một guard nhỏ hoặc thay đổi xử lý lỗi, không redesign endpoint.
Những thắng lợi nhanh đến từ prompt ép trích log, giữ giới hạn và dừng khi thiếu thông tin.
You are helping me fix a CI failure.
Repo context (short):
- Language/framework:
- Test/build command that failed: <PASTE THE EXACT COMMAND>
- CI environment (OS, Node/Go/Python versions, etc.):
Failing output (verbatim, include the first error and 20 lines above it):
<PASTE LOG>
Constraints:
- Propose the smallest possible code change that makes CI pass.
- Do NOT rewrite/refactor unrelated code.
- Do NOT touch files you do not need for the fix.
- If behavior changes, make it explicit and justify why it is correct.
Stop rule (no guessing):
- If the log is incomplete or you need more info (missing stack trace, config, versions, failing test name), STOP and ask only the minimum questions needed.
Your response format (follow exactly):
1) Evidence: Quote the exact log lines that matter.
2) Hypothesis: Explain the most likely cause in 2-4 sentences.
3) Smallest fix: Describe the minimal change and why it addresses the evidence.
4) Patch: Provide a unified diff.
5) Follow-up: Tell me the exact command(s) to rerun locally to confirm.
Then, write ONE regression test (or tweak an existing one) that would fail before this fix and pass after it, to prevent the same failure class.
- Keep the test focused. No broad test suites.
- If a test is not feasible, explain why and propose the next-best guardrail (lint rule, type check, assertion).
Hai chi tiết giảm thiểu back-and-forth:
Cách nhanh nhất để mất thời gian là chấp nhận một bản "dọn dẹp" sửa nhiều thứ cùng lúc. Định nghĩa "tối thiểu" ngay từ đầu: diff nhỏ nhất khiến job fail thành pass, rủi ro thấp nhất và dễ xác minh nhất.
Một quy tắc đơn giản: sửa triệu chứng trước, rồi quyết định refactor có đáng làm không. Nếu log chỉ ra một file, một function, một import thiếu, hoặc một edge case, aim vào đó. Tránh các chỉnh sửa "nhân tiện".
Nếu thực sự cần lựa chọn, yêu cầu hai phương án thôi: "an toàn nhất" vs "nhanh nhất". Bạn muốn tradeoff chứ không phải menu.
Yêu cầu luôn xác minh local bằng cùng lệnh pipeline chạy (hoặc gần nhất) để bạn có thể confirm trong vài phút:
# run the same unit test target CI runs
make test
# or the exact script used in CI
npm test
Nếu phản hồi đề xuất thay đổi lớn, phản hồi lại bằng: "Cho patch nhỏ nhất sửa assertion fail, không format hay đổi tên không liên quan."
Sửa mà không có test là cược rằng lỗi sẽ không lặp lại. Luôn yêu cầu test hồi quy fail trước sửa và pass sau.
Hãy cụ thể về tiêu chí "tốt":
Một pattern hữu ích: yêu cầu bốn thứ: nơi đặt test, tên file test, hành vi cần cover, và một ghi chú ngắn giải thích vì sao test ngăn lỗi tương tự.
Copy-ready add-on:
Ví dụ: CI báo panic khi handler API nhận ID rỗng. Đừng chỉ yêu cầu "một test cho dòng này." Yêu cầu test cho ID không hợp lệ (rỗng, chỉ whitespace, sai format). Sửa nhỏ nhất có thể là guard clause trả 400. Test theo sau assert hành vi cho nhiều input không hợp lệ, vậy nếu ai đó refactor parsing, CI sẽ fail ngay.
Nếu repo đã có convention test, nêu ra. Nếu không, yêu cầu mirror test gần đó và giữ test mới tối thiểu, rõ ràng.
Dán đoạn log CI gồm lỗi và 20–40 dòng phía trên. Đồng thời dán lệnh CI chạy và các chi tiết môi trường quan trọng (OS, phiên bản runtime, flag quan trọng).
Rồi yêu cầu model tóm lại bằng lời thường những gì fail và trỏ tới dòng(s) trong output chứng minh nó. Nếu nó không trích log, nó chưa thật sự đọc.
Yêu cầu sửa nhỏ nhất khiến lệnh fail pass. Phản đối refactor. Trước khi apply, bắt nó liệt kê:
Áp patch và chạy cùng lệnh fail local (hoặc cùng job CI nếu đó là lựa chọn duy nhất). Nếu vẫn fail, dán chỉ output mới và lặp lại. Giữ ngữ cảnh nhỏ giúp phản hồi tập trung.
Khi xanh, thêm một test theo sau mà sẽ fail trước sửa và pass sau. Giữ tập trung: một test, một lý do.
Chạy lại lệnh để confirm bạn không chỉ im lặng lỗi.
Yêu cầu một commit message ngắn và mô tả PR bao gồm: cái gì fail, thay đổi gì, bạn đã xác minh thế nào, và test nào ngăn lặp lại. Reviewer xử lý nhanh hơn khi lý do rõ ràng.
Một failure thường gặp: mọi thứ chạy ổn local, rồi một thay đổi nhỏ làm tests fail trên runner CI. Dưới đây là ví dụ Go API nơi handler bắt giá trị date-only (2026-01-09) nhưng code vẫn chỉ parse RFC3339 đầy đủ.
Đây là đoạn ngắn bạn nên dán (giữ ngắn nhưng có dòng lỗi):
--- FAIL: TestCreateInvoice_DueDate (0.01s)
invoice_test.go:48: expected 201, got 400
invoice_test.go:49: response: {"error":"invalid due_date: parsing time \"2026-01-09\" as \"2006-01-02T15:04:05Z07:00\": cannot parse \"\" as \"T\""}
FAIL
exit status 1
FAIL app/api 0.243s
Bây giờ dùng một prompt ép bằng chứng, sửa tối thiểu và test:
You are fixing a CI failure. You MUST use the log to justify every claim.
Context:
- Language: Go
- Failing test: TestCreateInvoice_DueDate
- Log snippet:
<PASTE LOG>
Task:
1) Quote the exact failing line(s) from the log and explain the root cause in 1-2 sentences.
2) Propose the smallest possible code change (one function, one file) to accept both RFC3339 and YYYY-MM-DD.
3) Show the exact patch.
4) Add one regression test that fails before the fix and passes after.
Return your answer with headings: Evidence, Minimal Fix, Patch, Regression Test.
Một phản hồi tốt sẽ chỉ ra mismatch layout khi parse, rồi chỉnh một function nhỏ (ví dụ parseDueDate trong invoice.go) để thử RFC3339 trước, fallback sang 2006-01-02. Không refactor, không package mới.
Test hồi quy là rào chắn: gửi due_date: "2026-01-09" và expect 201. Nếu ai đó sau này loại fallback, CI sẽ fail lại ngay.
Cách nhanh nhất để mất một giờ là dán view cắt xén của vấn đề. Log CI nhiều tiếng ồn, nhưng phần hữu ích thường là 20 dòng phía trên lỗi cuối.
Bẫy là chỉ dán dòng đỏ cuối (ví dụ, "exit 1") trong khi che nguyên nhân thực sự trước đó (env var thiếu, snapshot fail, hoặc test crash). Fix: bao gồm lệnh fail và cửa sổ log nơi first real error xuất hiện.
Một lãng phí thời gian khác là để model "dọn dẹp" dần dần. Format thêm, bump dependency, refactor làm cho review khó và dễ phá. Fix: khoá scope vào thay đổi nhỏ nhất và từ chối mọi thứ không liên quan.
Một vài pattern cần chú ý:
Nếu nghi ngờ flaky, đừng che bằng retry. Loại bỏ randomness (thời gian cố định, seed RNG, temp dir cô lập) để tín hiệu rõ ràng.
Trước khi push, làm một pass sanity ngắn. Mục tiêu là đảm bảo thay đổi thực, tối thiểu và có thể lặp lại, không một lần pass may mắn.
Cuối cùng, chạy một tập rộng hơn chút so với job fail ban đầu (ví dụ lint + unit tests). Một lỗi phổ biến là sửa xong job gốc nhưng phá target khác.
Nếu muốn tiết kiệm thời gian lâu dài, coi prompt và cấu trúc phản hồi như quy trình nhóm. Mục tiêu là input lặp được, output lặp được, và ít "sửa bí ẩn" làm vỡ chỗ khác.
Biến prompt tốt nhất thành snippet chia sẻ với team. Mọi người dùng cùng format: (1) evidence, (2) một câu nguyên nhân, (3) thay đổi nhỏ nhất, (4) test theo sau, (5) cách verify local. Reviewer nhanh hơn khi biết nhìn chỗ nào.
Một vòng thói quen nhẹ hiệu quả:
Nếu bạn thích workflow chat-first để build và iterate, có thể chạy cùng vòng fix-test trong Koder.ai, dùng snapshot khi thử nghiệm, và xuất source khi sẵn sàng merge về repo chính.
Bắt đầu từ lỗi thật sự đầu tiên, không phải dòng cuối cùng exit 1.
Hãy bắt nó chứng minh đã đọc log.
Dùng một ràng buộc như:
Mặc định là bản vá nhỏ nhất khiến bước thất bại thành công.
Thông thường là:
Tránh các thay đổi “dọn dẹp” cho đến khi CI xanh lại.
Dán đủ ngữ cảnh để tái tạo lỗi, không chỉ dòng đỏ cuối cùng.
Bao gồm:
go test ./..., , , v.v.).Có—nói rõ các ràng buộc bằng ngôn ngữ thẳng.
Ví dụ ràng buộc:
Điều này giữ phản hồi tập trung và dễ review.
Sửa lỗi sớm nhất trước.
Khi phân vân, yêu cầu model xác định bước fail đầu tiên trong log và sửa theo đó.
Xem flaky như tín hiệu để loại bỏ yếu tố ngẫu nhiên, không phải thêm retry.
Các biện pháp ổn định thường gặp:
Khi có độ xác định, sửa nhỏ nhất sẽ rõ ràng hơn.
Yêu cầu đúng lệnh CI rồi chạy lệnh đó tại local.
Nếu khó tái tạo local, yêu cầu một repro tối thiểu trong repo (một test hoặc target) gây ra cùng lỗi.
Viết một test hồi quy tập trung mà fail trước sửa và pass sau.
Mục tiêu tốt gồm:
Nếu là lỗi lint/build, “test” tương đương có thể là thắt chặt rule lint hoặc thêm check ngăn sai lặp lại.
Dùng snapshot/rollback để thử nghiệm có thể đảo ngược.
Một vòng thực tế:
Snapshot giúp lặp nhanh mà không trộn thử nghiệm vào patch cuối cùng bạn sẽ merge.
npm testflutter test