AIDive

Claude Code tung bug. Tôi khiến nó bất khả với 4 bản sửa

Bởi AIDive · Đăng ngày

Coding agent

Session đã tung ra bug, và retro bảo là suôn sẻ

Claude Code đã tung ra một bug đánh số trên một repo thật, và bốn thay đổi được duyệt khiến bug đó không thể lọt ra lần nữa. Session viết credit note cho một API hóa đơn nhỏ, bộ test báo xanh, rồi một bước kiểm tra chạy tay sau đó phát hiện một request bị từ chối đã đốt mất một số hóa đơn. Sau đó chúng tôi chạy retro trên session ấy, duyệt từng bản sửa một, và chạy lại đúng tác vụ cũ: kết quả sạch.

Retro là buổi review mà một team tổ chức sau sự cố, ở đây được chạy trên chính log session của Claude Code. Retro đầu tiên của chúng tôi mở đầu bằng "This session was smooth", và không phát hiện nào của nó là bug đó. Cách khắc phục là bảy thao tác, theo thứ tự: cài đặt, chạy tác vụ, chạy retro và nói cho nó biết điều gì đã hỏng, truy vết từng ứng viên, duyệt từng ứng viên sống sót vào một carrier, commit và audit, rồi chạy lại tác vụ.

Retro là gì, và cài đặt /retro

/retro là một skill của Matt Pocock dùng để review một session coding thay vì code của bạn. Nó đọc log session, tức là file mà Claude Code lưu cho mọi prompt và mọi lần gọi tool, và tìm các ứng viên trong bảy nhóm, chẳng hạn một bước kiểm tra lẽ ra có thể bắt được lỗi. Nó trình bày chúng theo mức độ nghiêm trọng và, theo tài liệu của nó, chỉ đề xuất: không có gì thay đổi cho đến khi bạn chọn một ứng viên.

Cài đặt là thao tác đầu tiên: trong repo của bạn, cập nhật marketplace chính thức, rồi cài skills pack ở phạm vi dự án để nó chỉ nằm trong repo này. Marketplace của chúng tôi bị ghim vào một bản phát hành cũ chưa có retro, nên phải cập nhật trước. Trong một session mới, gõ dấu gạch chéo và lệnh retro sẽ có trong danh sách.

Một giới hạn: session chạy trên cloud không đọc được log trên máy bạn, nên hãy chạy retro ở nơi session đã diễn ra.

Chạy tác vụ của bạn và để nó xong: session của chúng tôi tung ra bug

Thao tác thứ hai là việc bạn vẫn làm mỗi ngày: gõ tác vụ thật của bạn vào một session thường, để nó chạy xong, và giữ session mở, vì đó là thứ retro sẽ đọc.

Chúng tôi dùng một API hóa đơn nhỏ bằng Node và TypeScript, có bộ test riêng, không có file hướng dẫn, không có pipeline và không có commit hook ở bất cứ đâu. Tác vụ ngắn gọn, đúng kiểu bạn tự gõ: thêm credit note cho các hóa đơn đã thanh toán, đánh số theo thứ tự, và cho phép hủy một hóa đơn đã thanh toán bằng cách ghi có phần còn lại.

Session viết route, một migration và test của chính nó, rồi chạy bộ test trước khi dừng. Sau đó chúng tôi chạy bước kiểm tra mà bên finance sẽ chạy tay, một test ẩn viết sẵn từ trước, và một yêu cầu đã trượt.

Tín hiệu Kết quả
Bộ test 42 test qua
Type check sạch
Kiểm tra ẩn của finance trượt: số credit note lớn hơn mong đợi

Nguyên nhân: handler lấy số kế tiếp từ counter trước khi validate request, và counter được lưu ngay khi được đọc. Một credit note quá lớn bị từ chối, điều đó đúng, nhưng con số vẫn mất, điều đó thì sai. Session đã chép thứ tự đó từ route issue có sẵn, vốn làm rò số hóa đơn theo cùng một cách.

Chúng tôi chạy tác vụ này hai lần và lần còn lại cho kết quả sạch, nên đây là điều một session thường thỉnh thoảng vẫn làm.

Chạy /retro, rồi nói cho nó biết điều gì đã hỏng

Thao tác thứ ba là gõ lệnh retro ngay trong session đó, rồi chạy lại với lỗi được viết ngay sau lệnh. Retro của chúng tôi mở đầu bằng: "This session was smooth."

Nó xếp hạng vài mục, không mục nào là bug: một guardrail còn thiếu, một quy tắc migration không ai kiểm, và không có gì để reviewer áp dụng. Retro đọc log session, và session chưa bao giờ biết mình đã hỏng.

Vậy nên bạn phải nói cho nó: chạy lại lệnh với lỗi làm argument, tức là phần văn bản sau lệnh. Của chúng tôi nói rằng finance đã test bản build, rằng một credit note quá lớn bị từ chối, rằng credit note hợp lệ kế tiếp ra số trễ, và rằng retro không được sửa gì cả.

Lần này nó tìm ra nguyên nhân trong chính code của nó: nó lấy số trước rồi validate sau, và nó nói đã chép thứ tự đó từ handler issue có sẵn. Các ứng viên mới xuất hiện: một test nó đã viết chạy đúng chuỗi bị lỗi nhưng chỉ kiểm tra status code, một hàm counter trông thuần khiết mà không phải, và một quy ước chưa ai viết ra.

Bất cứ điều gì bạn phát hiện sau session, hãy gõ vào argument, nếu không retro sẽ audit một session mà nó tin là đã ổn.

Truy vết mọi ứng viên tới một khoảnh khắc trước khi duyệt

Thao tác thứ tư là thứ mà skill không tự làm: yêu cầu retro trích dẫn khoảnh khắc trong transcript đứng sau từng ứng viên, và loại mọi ứng viên mà nó không chỉ ra được.

Tài liệu giải thích vì sao một danh sách xếp hạng thôi là chưa đủ: khi công việc đã xong, model quên những khó khăn của session và bịa ra lời khuyên chung chung. Vì thế hãy loại mọi ứng viên bạn không truy được về một khoảnh khắc cụ thể: một câu yêu cầu retro trích transcript cho từng cái.

Ở retro đầu tiên của chúng tôi, câu trả lời rất thẳng: phần lớn ứng viên không có căn cứ trong transcript. Nó giữ lại guardrail còn thiếu, vì chính lệnh liệt kê thư mục hook của nó không in ra gì, và loại bước kiểm tra migration vì chỉ là giả định.

Ở retro thứ hai, cái đã biết về bug, bước truy vết giữ lại bốn ứng viên và loại một.

Ứng viên Sau khi truy vết
Test nó đã viết (chấp nhận, từ chối, chấp nhận, số không bao giờ được kiểm) giữ, chắc chắn
Hàm counter không có cảnh báo giữ, chắc chắn
Quy ước chưa viết ra giữ, yếu hơn
Guardrail còn thiếu giữ, dù nó nói một guardrail sẽ không bắt được bug này
Ứng viên cuối bị loại: nó tính cùng một khoảnh khắc hai lần

Một issue đang mở trên repo của skill thống kê phần lớn các lần chạy retro đều được theo sau bởi việc người dùng đòi bằng chứng. Một ứng viên đã truy vết vẫn là model đang đọc log của chính nó, nên một dòng được đánh dấu yếu hơn là một phán đoán, và bạn quyết định mang cái nào đi tiếp.

Duyệt từng ứng viên sống sót vào carrier của nó

Thao tác thứ năm là nơi vòng lặp sinh lợi: duyệt từng ứng viên sống sót một, mỗi cái vào carrier của nó, nơi quy tắc sẽ sống. Skill cho bạn cái thang quyết định. Một vi phạm cơ học nhận một bước kiểm tra tất định, chấm hết: một quy tắc trong linter, một commit hook, hoặc một job trong pipeline. Một phán đoán đi vào file coding standards mà reviewer đọc. File hướng dẫn của bạn được dùng, theo lời tài liệu, "incredibly sparingly", cho các con trỏ tới file khác.

Chúng tôi đã duyệt bốn thay đổi:

  • Guardrail còn thiếu trở thành một commit hook được git theo dõi, chạy type check và các test rồi chặn commit nếu một trong hai thất bại. Harness từ chối cấp quyền thực thi cho file, nên chúng tôi tự chạy lệnh đó.
  • Test trở thành một test vitest khóa quy tắc: một credit note được chấp nhận, một credit note bị từ chối, và credit note hợp lệ kế tiếp phải mang số kế tiếp. Nó thất bại ở lần chạy đầu tiên, và đó chính là điểm mấu chốt: nó bắt được bug mà session đã tung ra.
  • Phán đoán trở thành một dòng trong CODING_STANDARDS.md mới: chỉ lấy số thứ tự sau khi mọi bước validate đã qua, để một request bị từ chối không để lại khoảng trống trong dãy số.
  • Khoảng trống điều hướng trở thành một comment phía trên hàm counter: nó lưu counter ngay lập tức, nên số đã bị tiêu dù bên gọi sau đó thất bại, vì vậy chỉ gọi sau khi validate.

Tức là bốn file thay đổi và không dòng nào trong CLAUDE.md, vì cả hai retro đều từ chối viết một dòng. Retro đầu nói một con trỏ trong steering file sẽ tốn context ở mỗi lượt và dần lỗi thời; retro thứ hai nói hãy giữ nó dưới dạng comment trên hàm. Tài liệu ủng hộ họ: Claude coi các file đó là context, không phải cấu hình bắt buộc, và để chặn một hành động thì bạn dùng hook.

Hai giới hạn: hook chỉ bảo vệ các commit, và comment, theo chính lời retro, là một canh bạc vào bên gọi kế tiếp, không phải bản sửa đã được chứng minh.

Khép vòng lặp: hook chặn commit, audit, commit, chạy lại

Thao tác thứ sáu là commit, và thao tác cuối là chạy lại đúng tác vụ đó, nơi bạn biết vòng lặp có giữ được hay không.

Khi chúng tôi stage các file đã duyệt và commit, hook chạy trước và từ chối commit. Type check qua, rồi test đánh số mới thất bại, nhận một số lớn hơn mong đợi. Hook kiểm tra các file như chúng đang có trên đĩa, và đĩa vẫn chứa code lỗi.

Nên hãy quay lại session và chỉ yêu cầu bản sửa: lấy số sau khi validate qua, chạy các bước kiểm tra, đừng commit. Rồi commit lại, hook chạy xanh, và bạn có hai commit: các thay đổi của retro, rồi tính năng cùng bản sửa của nó. Bản thân retro không commit gì cả, điều mà một issue đang mở trên repo mô tả từng chữ, nên bạn tự commit.

Tiếp theo, chạy /doctor prompt-audit, bước kiểm tra riêng của Claude Code cho các file hướng dẫn của bạn để tìm dòng lỗi thời. Có một cái bẫy ở đây: không có path, nó audit các file global của bạn, không phải repo. Khi được đưa path, nó báo file standards mới là sạch, và chỉ ra rằng route issue cũ vi phạm quy tắc, đó là bug trong code chứ không phải vấn đề của prompt.

Thao tác cuối là một session mới với cùng tác vụ. Session của chúng tôi đã đọc file coding standards, readme, hook và test đánh số đang đỏ trước khi viết bất kỳ dòng code nào, rồi tự ghi trong phần tóm tắt rằng số chỉ được lấy sau khi tất cả các bước kiểm tra đó qua, nên một request bị từ chối không để lại khoảng trống trong dãy số.

Session đầu tiên Session mới sau vòng lặp
Test qua 42 xanh
Kiểm tra ẩn của finance trượt 5 trên 5
Số sau một request bị từ chối bị đốt, có khoảng trống liền mạch

Một lưu ý trung thực: session mới này đã được trao bài học dưới dạng một test đỏ và một dòng standards, nên đây là một lần chạy sau vòng lặp, không phải benchmark.

Kết luận: khi nào chạy retro, khi nào không, một quy tắc

Retro đọc session, nên những gì session không nhìn thấy thì bạn phải viết vào argument. Đó là phần bạn sẽ vấp.

Hãy chạy retro sau một session đã đi sai, trước khi bạn xóa nó, hoặc trên log của session cũ. Đừng chạy nó tự động hay gắn vào hook: tác giả của skill nói thẳng bằng lời của mình, bạn không muốn tự động hóa việc này. Tài liệu thêm một giới hạn: nó không audit các bước kiểm tra nó đã đề xuất tháng trước, nên bạn vẫn phải tự tỉa chúng.

Quy tắc cần nhớ là chính câu của tài liệu: hãy đối xử với file hướng dẫn như code, xem lại khi có chuyện sai, tỉa thường xuyên, và kiểm thử thay đổi bằng cách quan sát xem hành vi của Claude có thực sự dịch chuyển không. Vòng lặp không làm agent đúng, nó làm cho cùng một cái sai bị bắt nhanh hơn, và các bước kiểm tra bạn thêm vào là code mà giờ bạn phải bảo trì.

Gói miễn phí cho video này có checklist retro với mọi thao tác, câu hỏi truy vết và các carrier, cùng script commit hook và test đánh số từ lần chạy của chúng tôi, để bạn bắt đầu từ bản của chúng tôi.

Tài nguyên miễn phí

Nguồn

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

Skill /retro của Matt Pocock làm gì?
Nó review một session Claude Code thay vì code của bạn, bằng cách đọc log session ghi mọi prompt và mọi lần gọi tool. Nó tìm ứng viên trong bảy nhóm, xếp hạng theo mức độ nghiêm trọng, và chỉ đề xuất: không có gì thay đổi cho đến khi bạn chọn một ứng viên.
Vì sao retro bảo session suôn sẻ?
Retro đọc log session, và session của chúng tôi chưa bao giờ biết mình đã hỏng: 42 test và type check đều xanh. Chỉ bước kiểm tra ẩn của finance bắt được bug, nên retro đầu tiên mở đầu bằng 'This session was smooth' và bỏ sót nó.
Làm sao để retro tìm ra lỗi mà session không thấy?
Chạy lệnh retro lần thứ hai và viết lỗi ngay sau lệnh làm argument. Của chúng tôi nói finance thấy một credit note bị từ chối và số kế tiếp ra trễ, và lần này retro truy nguyên nhân về chính code của nó lấy số trước khi validate.
Làm sao để retro chứng minh các phát hiện của nó?
Yêu cầu nó trích khoảnh khắc trong transcript đứng sau từng ứng viên và loại những cái nó không chỉ ra được. Ở retro đầu tiên của chúng tôi phần lớn ứng viên không có căn cứ; ở retro thứ hai bước truy vết giữ lại bốn và loại một.
Có nên đặt quy tắc vào CLAUDE.md không?
Không phải mặc định: chúng tôi duyệt bốn thay đổi và không viết dòng nào trong CLAUDE.md. Tài liệu nói Claude coi nó là context, không phải cấu hình bắt buộc, nên quy tắc cơ học thuộc về hook hoặc test và phán đoán thuộc về file coding standards.
Khi nào nên chạy retro trên một session Claude Code?
Chạy sau một session đã đi sai, trước khi bạn xóa nó, hoặc trên log của session cũ. Đừng tự động hóa hay gắn vào hook: tác giả của nó nói bạn không muốn tự động hóa việc này.

Video liên quan