6 phút

Claude Code cho lỗi CI: lời nhắc để sửa nhỏ nhất + test

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.

Claude Code cho lỗi CI: lời nhắc để sửa nhỏ nhất + test

Điều gì sai khi CI fail và AI đoán mò

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:

  • Đọc đầu ra lỗi.
  • Xác định thay đổi nhỏ nhất khiến bước thất bại thành công.
  • Giữ mọi thứ khác y nguyê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.

Những gì cần thu thập trước khi bạn yêu cầu giúp đỡ

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ể):

  • Toàn bộ log fail từ dòng lỗi đầu tiên tới hết (không chỉ stack trace cuối cùng).
  • Lệnh chính xác CI chạy (ví dụ, go test ./..., npm test, flutter test, golangci-lint run).
  • Đường dẫn file được nhắc trong lỗi, cùng config liên quan (test config, linter config, build scripts).
  • Những gì thay đổi gần đây: tóm tắt diff PR, bump dependency, chỉnh sửa config CI.
  • Có phải flaky không: nếu có hai ba lần fail và một lần pass thì nói rõ.

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):

Các quy tắc prompt khiến model phải đọc log lỗi

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ĩ.

Quy tắc giữ model trung thực

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:

  • Trích đúng các dòng lỗi từ log CI (lỗi, stack trace, file:line) và nói rõ "Tôi đang dùng những dòng này."
  • Cho một câu chẩn đoán, không vòng vo.
  • Đề xuất kế hoạch patch tối thiểu với 1–3 chỉnh sửa, nêu rõ file sẽ chạm vào.
  • Tránh thay đổi không liên quan (không format, không đổi tên, không refactor, không bump dependency) trừ khi bạn đồng ý.
  • Liệt kê những gì nó không chắc và một chi tiết duy nhất sẽ xác nhận chẩn đoán.

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.

Đoạn prompt sẵn dùng (copy-ready)

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.

Mẫu prompt copy-paste để xử lý lỗi CI

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:

  • Bao gồm lệnh fail chính xác và lỗi đầu tiên (không chỉ tóm tắt cuối cùng).
  • Nếu có nhiều failure, nói rõ fix nào ưu tiên (thường là lỗi thực sự sớm nhất trong log).

Cách thúc đẩy sửa nhỏ nhất, không redesign

Lên kế hoạch thay đổi tối thiểu
Lên outline 1–3 chỉnh sửa nhắm mục tiêu trước khi động vào code, rồi chỉ thực hiện những thay đổi đó.

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."

Prompt cho test theo sau ngăn lặp lại

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":

  • Nếu failure là crash unit test, thường cần test mới hoặc assert mạnh hơn.
  • Nếu failure là build, lint, hoặc rule format, cần check ép luật tương ứng.

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:

  • Viết một test hồi quy fail trên branch main hiện tại và pass sau khi sửa.
  • Nhắm tới class lỗi, không chỉ dòng lỗi cụ thể.
  • Đặt test vào: <path or folder>. Theo convention tên: <your convention>.
  • Nếu là lint/build, thêm hoặc chỉnh rule enforce phù hợp.
  • Thêm 2-3 câu: vì sao test này sẽ bắt lỗi tương tự sau này.

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.

Một workflow từng bước bạn có thể tái sử dụng

1) Dán lỗi như hiện tại

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.

2) Ép sửa nhỏ nhất trướ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ê:

  • File(s) sẽ chạm tới
  • Hành vi chính xác thay đổi
  • Những gì không thay đổi

3) Chạy lại cùng lệnh, giữ vòng ngắn

Á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.

4) Thêm test hồi quy cho class lỗi

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.

5) Hoàn tất với PR packet gọn

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.

Ví dụ thực tế: từ output fail tới sửa và test

Xây app nhanh hơn, sửa nhỏ hơn
Làm việc trên web, server hoặc mobile qua chat trong khi giữ thay đổi nhỏ và dễ review.

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.

Những sai lầm phổ biến tốn thời gian (và cách tránh)

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ú ý:

  • Chỉ dán dòng lỗi cuối: bao gồm lệnh fail và lỗi đầu tiên.
  • Để nó thay dependency hoặc file không liên quan: yêu cầu diff nhỏ nhất và lý do cho mỗi file chạm vào.
  • Chấp nhận sửa không verify bằng lệnh CI: chạy lại cùng lệnh và confirm.
  • Viết test mà sẽ vẫn pass khi bug quay lại: yêu cầu test fail trên code cũ và pass trên code mới.
  • Trộn flaky với regression thật: quyết xem đó là nondeterministic (timing, network, order) hay logic ổn định rồi xử lý phù hợp.

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.

Kiểm tra nhanh trước khi push bản vá

Giữ vòng lặp sửa nhỏ gọn
Xây và điều chỉnh app mà không phải nhảy giữa editor, terminal và tài liệu.

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.

  • Bằng chứng: giải thích có trích đúng các dòng lỗi không?
  • Phạm vi: thay đổi có giới hạn vào những gì cần để dừng lỗi không?
  • Nhân quả: có giải thích vì sao thay đổi này làm từ fail → pass không?
  • Repro: bạn đã chạy lại cùng lệnh CI (cùng flag, cùng working dir)?
  • Regression: test mới fail trên code cũ và pass sau khi sửa?

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.

Bước tiếp theo: biến workflow này thành thói quen

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ả:

  • Lưu prompt làm snippet repo và ghim trong chat nhóm.
  • Gắn nhãn lỗi CI theo loại (lint, unit, integration, packaging, deploy).
  • Khi label lặp lại, thêm test hoặc check bắt lỗi sớm hơn.
  • Giữ thử nghiệm rủi ro có thể hoàn tác để quay lại nhanh.

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.

Câu hỏi thường gặp

Nên xem chỗ nào trong log CI trước tiên khi một job bị fail?

Bắt đầu từ lỗi thật sự đầu tiên, không phải dòng cuối cùng exit 1.

  • Tìm dòng sớm nhất cho biết cái gì bị lỗi (tên test, file:line, lệnh).
  • Đọc khoảng ~20–40 dòng phía trên nó để lấy bối cảnh/thiết lập.
  • Bỏ qua các lỗi “dội” phía sau cho tới khi sửa được lỗi đầu tiên.
Làm sao để ngăn AI đoán mò và đưa ra sửa chữa chung chung?

Hãy bắt nó chứng minh đã đọc log.

Dùng một ràng buộc như:

  • “Trích đúng các dòng lỗi bạn đang dùng.”
  • “Chuẩn đoán bằng một câu.”
  • “Sửa nhỏ nhất: 1–3 chỉnh sửa với đường dẫn file chính xác.”
  • “Dừng lại và hỏi nếu log thiếu thông tin.”
“Sửa nhỏ nhất” thực tế nghĩa là gì cho lỗi CI?

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à:

  • Một thay đổi code nhắm mục tiêu (khai báo guard clause, import thiếu, đường dẫn sai).
  • Một điều chỉnh cấu hình dành riêng cho CI.
  • Hoàn tác một thay đổi phá vỡ thay vì thiết kế lại.

Tránh các thay đổi “dọn dẹp” cho đến khi CI xanh lại.

Tôi nên bao gồm gì khi yêu cầu trợ giúp về một lần chạy CI bị fail?

Dán đủ ngữ cảnh để tái tạo lỗi, không chỉ dòng đỏ cuối cùng.

Bao gồm:

  • Lệnh CI chính xác (go test ./..., npm test, flutter test, v.v.).
  • Log từ dòng lỗi đầu tiên tới cuối.
  • Đường dẫn file được nhắc trong lỗi.
  • Những thay đổi gần đây (bump dependency, sửa CI config, tóm tắt PR).
  • Có phải flaky không (vài lần fail + một lần pass).
Tôi có thể nói rõ với model là không được refactor hoặc reformat không?

Có—nói rõ các ràng buộc bằng ngôn ngữ thẳng.

Ví dụ ràng buộc:

  • “Không refactor, không đổi tên, không format, không bump dependency.”
  • “Chỉ chạm vào file cần cho bản vá.”
  • “Nếu thay đổi hành vi, mô tả chính xác thay đổi và lý do.”

Điều này giữ phản hồi tập trung và dễ review.

Nếu CI hiển thị nhiều lỗi, tôi nên sửa cái nào trước?

Sửa lỗi sớm nhất trước.

  • Các lỗi sau thường do lỗi đầu tiên gây ra (ví dụ, build fail → tests/lint không chạy đúng).
  • Nếu lỗi độc lập, chọn cái ảnh hưởng chặn nhất (thường build/lint trước integration).

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 đó.

Làm sao biết một thất bại CI là flaky, và nên làm gì?

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:

  • Khóa thời gian (inject clock, dùng timestamp cố định).
  • Seed RNG.
  • Tránh gọi mạng (mock/stub).
  • Dùng temp dir cô lập và port duy nhất.

Khi có độ xác định, sửa nhỏ nhất sẽ rõ ràng hơn.

Cách tốt nhất để xác minh bản vá trùng với CI và không phải pass may mắn là gì?

Yêu cầu đúng lệnh CI rồi chạy lệnh đó tại local.

  • Dùng cùng lệnh và flag như CI.
  • Khớp các phiên bản môi trường quan trọng khi có thể (Go/Node/Flutter, OS).

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.

Test theo sau tốt nhất sau khi sửa lỗi CI là gì?

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:

  • Edge case gây lỗi (input null, timezone, làm tròn, quyền).
  • Một lớp lỗi rộng hơn (ví dụ, nhiều ID không hợp lệ, không chỉ một).

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.

Làm sao lặp nhanh mà không làm repo lộn xộn khi debug CI?

Dùng snapshot/rollback để thử nghiệm có thể đảo ngược.

Một vòng thực tế:

  • Thực hiện thay đổi nhỏ nhất.
  • Chạy lệnh CI bị lỗi.
  • Nếu vẫn fail, revert về snapshot trước và thử patch khác.

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.

Related posts