Skip to content

ship: verify và mở PR ​

/znf:ship là bước cuối của mọi workflow. Nó chạy lint, build, contract gate, verify hành vi (gồm kiểm thử UI khi diff chạm giao diện) và review độc lập, rồi commit, push và mở PR. Ship không merge.

Khi nào dùng ​

Dùng /znf:ship khi code đã xong và sắp commit. Ba workflow /znf:cook, /znf:fix, /znf:hotfix gọi ship ở bước cuối. Khi đi đường không dùng workflow, bạn tự gọi.

Không dùng /znf:ship khi chưa verify được gì. Ship không thay thế bước tự chạy thử code.

Cách gọi ​

text
/znf:ship

Agent tự route vào ship khi code xong, bạn không cần gõ lệnh. Ba workflow còn lại gọi ship vô điều kiện ở bước cuối.

Viết yêu cầu ​

Ship tự suy ra phạm vi từ file đã đổi. Bạn không cần liệt kê gì thêm.

TrườngNội dung
IntentĐường dẫn plan nếu tới từ /znf:cook. Nguyên nhân đã xác nhận nếu tới từ /znf:fix hoặc /znf:hotfix. Mục tiêu bạn nêu ra nếu đi đường không dùng workflow

Các bước ​

Các bước của một lần chạy ship

BướcKit làm gìBạn làm gì
1Xác định vùng thay đổi từ file đã đổiKhông cần làm gì
2Lint và build/typecheck vùng đó, lấy output thậtĐọc output
3Nếu chạm DB collection, endpoint, queue hoặc channel chung, chạy contract gateĐọc repo nào bị ảnh hưởng
4Verify hành vi: test bị ảnh hưởng so với base (hotfix: full suite), hoặc /znf:run. Nếu diff chạm giao diện, ship kiểm thử UI — golden-diff zenify visual check (khi repo có .znf/visual/routes.json) rồi znf:ui-verifier đo overflow phần tử đã đổi. Chi tiết ở Kiểm thử UIĐọc kết quả, kể cả số liệu overflow nếu là UI
5Review độc lập (gói ý định của /znf:fix và /znf:hotfix có dòng Loop:/Regression:) trên diff tính từ git merge-base "$(zenify wt base)" HEAD (xem base thật của worktree), nên commit mới trên base không hiện thành xoá giả. CRITICAL/HIGH vào vòng sửa, MEDIUM/LOW lên boardĐọc finding
Vòng sửaSửa hết finding mở trong một wave, chạy lại check liên quan, tối đa 2 vòngNếu còn mở sau vòng 2, ship dừng, không commit, và báo bạn
6Xác định thứ tự deploy (đa service)Đọc thứ tự
7Ghi board vào file, commit và push branch, mở PR với body gồm tóm tắt, thay đổi, cách kiểm, rủi ro merge (một chiều/hai chiều) (không chép SC, tên test hay dòng ledger)Đọc board bằng cat, không đọc bản tóm tắt. Nhận PR URL

Gắn issue GitHub (tuỳ chọn) ​

Mặc định ship mở PR như trên. Khi bạn bật tính năng github.issues, phiên có dòng features: github.issues on (worker được giao việc nhận dòng Features: github.issues on trong brief) và ship gắn một issue GitHub trước khi mở PR. Bật bằng:

bash
zenify feature github.issues on

Tắt bằng zenify feature github.issues off; zenify feature không đối số liệt kê trạng thái từng tính năng. Trạng thái nằm ở khóa features: trong .zenify-overlay.yaml.

Khi tính năng bật, ship tìm issue theo thứ tự: số issue bạn đưa trong phiên (kể cả dòng Issue: <owner>/<repo>#N trong brief giao worker), rồi issue nêu trong spec hoặc ledger SDD, rồi mới tạo mới. Trước khi tạo, ship kiểm trùng bằng gh issue list --search và gh pr list --search theo slug của branch; chỉ hai lệnh này quyết định, có hit thì ship dừng và hỏi bạn, kèm URL đầy đủ của từng hit. Issue mới được assign cho bạn (--assignee @me), tiêu đề lấy từ phần mô tả của tiêu đề PR, body lấy từ Problem trong Brief của spec, không gắn label; body được ghi ra file tạm rồi truyền qua --body-file, không bao giờ nhét văn bản tự do vào tham số shell trong ngoặc kép. Body PR có dòng Closes #N khi PR cùng repo với issue, Closes <owner>/<repo>#N khi PR ở repo khác (không dùng Refs #N). Nếu bạn nói không cần issue thì ship bỏ qua bước này và ghi lý do trong body PR.

  • Base không phải default branch: issue chỉ tự đóng khi commit tới default branch, ship nói rõ điều này trong báo cáo.
  • Stacked PR: một issue cho cả stack, Closes #N chỉ nằm trong body của PR lớp trên cùng.
  • Ship báo mọi issue và PR bằng URL đầy đủ.

Mã ticket trong tiêu đề PR ​

Khi tên branch có zen-<n> ở ranh giới slug (regex (^|[/-])zen-(\d+)(-|$), không phân biệt hoa thường, ví dụ <user>/fix/zen-123-foo; frozen-12-x, citizen-3, dozen-5 không khớp; nhiều chỗ khớp thì lấy chỗ đầu tiên), ship đặt mã viết hoa ngay sau dấu hai chấm: <type>(<scope>): ZEN-<n> <mô tả>. Mã đó (nếu có) đứng đầu; ship cộng thêm mọi mã trong dòng **Việc Plane:** của spec/plan (/cook) hoặc phần ## Intent của ship-pack (/fix, /hotfix), bỏ trùng (branch không có mã thì các mã trong dòng đó là mã của tiêu đề), nên tiêu đề có thể là <type>(<scope>): ZEN-<a>, ZEN-<b> <mô tả>; mã luôn ngay sau dấu hai chấm, không bao giờ ở cuối, và ship không quét ZEN-n ở chỗ khác (dòng **Liên quan:** không tính). Không có mã nào thì tiêu đề giữ nguyên, không cảnh báo. Với stacked PR, thân PR của mọi lớp trừ lớp trên cùng có dòng Part of ZEN-<n>.

Stacked PR ​

Khi plan có khối ## Stack, ship đổi vài chỗ của luồng trên; plan không có khối này thì luồng một PR giữ nguyên.

  • Bước 2-4 chạy một lần trên lớp trên cùng, nơi thấy cả stack.
  • Bước 5 chạy riêng cho từng lớp, từ dưới lên: diff của lớp i tính từ lớp i-1 (lớp 1 tính từ base ref). Lớp nào quá lớn để review thì ship dừng và đề xuất tách lớp đó. Gói review của mỗi lớp chỉ mang các mục deferred/parked của task thuộc lớp đó; mục không gắn task nằm ở lớp trên cùng.
  • Sửa một finding thuộc lớp thấp hơn thì kit sửa ở lớp đó, gh stack rebase --upstack, rồi review lại lớp đó và các lớp trên. Rebase conflict thì kit abort, không tự giải, không push và báo bạn.
  • Bước 7 ghi một dòng gate log cho cả lần ship và điền board trước khi push gì; board có một dòng mỗi lớp, ban đầu là <pending>. Có ❌ thì ship dừng và không push. Board xanh thì ship mở stack bằng gh stack submit --auto --open (thay cho push và gh pr create), rồi đặt title cho từng PR theo dòng của lớp đó trong khối ## Stack của plan và body ghi lớp i/N, sau cùng thay <pending> bằng URL PR.

Bạn merge stack từ dưới lên; merge PR N thì mọi PR chưa merge bên dưới nó cũng được merge theo. Agent không merge và không chạy gh stack merge.

Kết quả ​

ArtifactNội dung
Board${TMPDIR:-/tmp}/ship-board-<fp10>.md. Mọi dòng ✅/❌ kèm fingerprint. Đọc bằng cat, không tóm tắt
PRMở, chưa merge. Plan có ## Stack: một PR mỗi lớp, từ dưới lên

Sau khi mở PR: --watch ​

/znf:ship --watch gọi znf:ci-watch sau khi mở PR. Khi feature track bật (zenify feature track on), ship coi như luôn có --watch và truyền id track cho ci-watch để ghi kết quả CI vào sổ (zenify track ci). Ngoài chờ CI xanh, ci-watch còn chờ PR ở trạng thái CLEAN (CI xanh chưa đủ: review bắt buộc, review thread và check của app khác vẫn có thể chặn merge). Khi CLEAN, nó in URL PR đầy đủ và lệnh để bạn tự chạy: ! gh pr merge -R <owner/repo> <n> --merge. Bị chặn thì nó liệt kê review thread chưa resolve (hoặc check bắt buộc đang đỏ) rồi dừng; ci-watch không resolve thread và không merge. Xem ci-watch.

Nếu CLAUDE.md của project có dòng PR review check:, sau khi mở PR ship tự chờ đúng check review đó trên commit vừa push (tối đa 30 phút), sửa mọi finding blocking trong một commit mỗi vòng, tối đa 3 vòng, và chỉ chờ CI (như trên) khi check review đã xanh. Sau 3 vòng vẫn đỏ thì ship dừng và báo các finding còn mở. Không có dòng đó thì ship báo URL PR rồi dừng như cũ.

Quyết định thuộc về bạn ​

  • Merge PR. Ship không tự merge, kể cả PR nó vừa mở.
  • Xử lý finding còn mở sau vòng sửa thứ 2. Ship dừng và báo lại, không tự quyết.

Ví dụ ​

PR của chính site tài liệu này do ship mở, ở bước cuối của lần chạy /znf:cook xây site.

Lỗi thường gặp ​

TránhNên làm
Bỏ verify vì review sạchBoard phải đủ dòng: lint, build, contract gate, verify hành vi, review. Tất cả bắt buộc
Merge vì CI xanhĐọc board trước. CI xanh không thay thế review độc lập hay verify hành vi trong board

Xem thêm ​

/reference/skills/ship, Gate fail-open, Chọn workflow