# /generate-bdd — Sinh BDD Feature Files

## Gate
# Gate — Quy trình vào chuẩn cho mọi lệnh

Mọi lệnh PHẢI chạy gate này trước khi thực thi phần logic riêng của nó.

## Bước 0 — Kiểm tra chế độ Sub-Agent

Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ một orchestrator hay không:

1. Thử parse `$ARGUMENTS` dưới dạng JSON.
2. Nếu parse thành công **và** chứa `"_agent_mode": true`:
   - **Bỏ qua hoàn toàn Bước 1, 2 và 3 của Gate này.**
   - Đặt target file = `payload.target_file`
   - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
   - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
   - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
   - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
   - Đi thẳng tới phần logic riêng của lệnh.
3. Nếu `$ARGUMENTS` không phải JSON hoặc không có `_agent_mode` → tiếp tục sang Bước 1 (chế độ thường).

## Bước 0-B — Kiểm tra Model

*Bỏ qua bước này nếu `_agent_mode: true` (sub-agent — orchestrator đã kiểm tra rồi).*

Các lệnh sinh nội dung và review phức tạp đòi hỏi khả năng suy luận mạnh.
Dùng model nhỏ hơn sẽ rủi ro: bỏ sót edge case, phân tích spec thiếu sót, vi phạm kiến trúc.

Hiển thị và chờ phản hồi:

```
⚙️  MODEL CHECK
──────────────────────────────────────────────────────────────────
  Recommended  : claude-opus-4 (hoặc model Opus mới nhất)
  Why needed   : Phân tích spec, review kiến trúc, sinh code đòi hỏi
                 suy luận sâu. Model nhỏ hơn dễ bỏ sót edge case.

  Cách đổi trong Claude Code:
    • Settings → Model → chọn "claude-opus"
    • hoặc: /model → chọn claude-opus

  Đang chạy claude-opus?
    Y — đúng, đang dùng claude-opus → tiếp tục
    S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
──────────────────────────────────────────────────────────────────
```

- "Y" → tiếp tục sang Bước 1.
- "S" → tiếp tục sang Bước 1 (người dùng chấp nhận rủi ro, thêm ⚠️ vào report cuối).
- "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang claude-opus rồi chạy lại lệnh này."

## Bước 1 — Xác định Target File

1. Nếu `$ARGUMENTS` được cung cấp và trỏ tới một file tồn tại → dùng trực tiếp làm target.
2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
   - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
   - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
   - **Lệnh tech-docs**: `{specs_dir}/{domain}/*/tech-docs/{UC-ID}*-tech-design*.md`.
   - **Lệnh design-spec**: `{specs_dir}/{domain}/*/design-spec/{TICKET-ID}*.md`.

   Khi một file khớp: đặt nó làm target **và** ghi lại `domain` + `prd_slug` từ path của nó (theo quy tắc trích xuất trong `context-loader.md` Bước 1 — `prd_slug` = segment đầu tiên sau `{specs_dir}/{domain}/`). Mọi path mà lệnh đọc/ghi về sau (BDD/tech-docs/design-spec/trace cùng cấp) đều dùng **`prd_slug` đã phân giải đó**, nên tất cả artifact nằm chung một feature package. Nếu nhiều file khớp (vd: nhiều platform), chọn theo platform/scope của lệnh hoặc liệt kê ra và hỏi.
3. Nếu `$ARGUMENTS` rỗng hoặc không tìm thấy file khớp:
   - Liệt kê các file trong thư mục liên quan của lệnh này (vd: `specs/*/*/*.md` — file PRD ở gốc mỗi feature folder — cho lệnh PRD, `specs/*/*/bdd/**/*.feature` cho lệnh BDD).
   - Hiển thị danh sách cho người dùng và hỏi: "Bạn muốn làm việc với file nào? (Nhập số thứ tự hoặc tên file)"
   - Chờ người dùng chọn rồi mới tiếp tục.

## Bước 2 — Chạy Context Loader

Nạp toàn bộ context của dự án bằng cách làm theo quy trình trong `steps/context-loader.md`.
Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phiên làm việc của lệnh.

## Bước 3 — CHECKPOINT

Sau khi hoàn thành Bước 1 và 2, hiển thị bản tóm tắt và chờ xác nhận:

```
CHECKPOINT
-----------
Target     : {resolved file path}
Project    : {project.name từ project-context.yaml}
Tech stack : {language} / {framework}
Module     : {module nếu có, else "not configured"}
Domains    : {danh sách domain, ngăn cách bởi dấu phẩy}

Tiếp tục? (Y/N)
```

Chờ người dùng trả lời rõ ràng "Y" hoặc "N" rồi mới tiếp tục.
- "Y" → tiếp tục sang các bước riêng của lệnh bên dưới.
- "N" → dừng lại và hỏi người dùng muốn thay đổi gì.


## Context
# Context Loader — Nạp toàn bộ context dự án

Thực hiện các bước theo đúng thứ tự. Lưu mọi thứ vào bộ nhớ trong suốt phiên làm việc của lệnh.

**Hướng dẫn ưu tiên (chống lost-in-middle):**
- Bước 1–2 là PROJECT-CONFIG — nạp trước, phân giải mọi path và metadata.
- Bước 3 là CRITICAL — kiến trúc + coding standards, là các sự thật ưu tiên cao nhất khi sinh nội dung.
- Bước 4 là SAFETY — quy tắc bảo vệ dữ liệu, thực thi ngầm suốt cả phiên.
- Bước 5–6 là DOMAIN KNOWLEDGE — thuật ngữ và định nghĩa entity.
- Bước 7 là WORKING MEMORY RECAP — chốt các sự thật quan trọng lên đầu bộ nhớ làm việc.

---

## Bước 1 — [PROJECT-CONFIG] Nạp project-context.yaml

Đọc `.agent/project-context.yaml`. Trích xuất và lưu:

**Tech Stack:**
- `tech_stack.language` → ngôn ngữ đang dùng (vd: Java 17, TypeScript, C#, Go)
- `tech_stack.framework` → framework đang dùng (vd: Spring Boot 3.2, Angular 17, .NET 8)
- `tech_stack.build_tool` → build tool (vd: Maven, npm, dotnet, go)
- `tech_stack.test_framework` → test framework (vd: JUnit 5 + Mockito, Jest, xUnit)
- `tech_stack.database` → database (vd: PostgreSQL, MySQL, MongoDB)
- `tech_stack.module` → module profile đang dùng (vd: java-spring, angular, dotnet, golang, context-engineering)

**Conventions:**
- `conventions.build_command` → cách compile/build
- `conventions.test_command` → cách chạy test
- `conventions.service_run` → cách khởi động service
- `conventions.ticket_prefix` → tiền tố ticket ID (vd: PROJ, FEAT, UC)

**Domains:**
- `domains` → danh sách các business domain đang hoạt động

**Paths (nếu có):**
- `paths.specs_dir` → gốc của spec artifact — PRD, BDD, tech-docs, design-spec. Cấu trúc: `{specs_dir}/{domain}/{prd-slug}/{ {TICKET-ID}-{prd-slug}.md | bdd/ | tech-docs/ | design-spec/}` (file PRD đặt tên `{TICKET-ID}-{prd-slug}.md`, là file `.md` duy nhất ở gốc feature folder)
- `paths.refinement_dir` → thư mục output cho findings/review
- `paths.qc_dir` → gốc artifact QC automation (hiện ở top-level, mỗi UC một thư mục con: `{qc_dir}/{UC-ID}/`)
- `paths.qc_skills_dir` → nơi các lệnh qc-* nạp QC skill (mặc định bundled `.agent/skills/qc`; override sang repo/submodule riêng của team QC để bản nâng cấp framework không ghi đè)
- `paths.product_definitions_dir` → gốc product definition
- `paths.domain_knowledge_dir` → gốc domain knowledge
- `paths.business_dictionary` → path tới business-dictionary.md
- `paths.core_entities` → path tới core-entities.md
- `paths.tech_docs_dir` → gốc tài liệu kỹ thuật (gộp với specs_dir trong bố cục feature-package — tech-docs nằm dưới `{specs_dir}/{domain}/{prd-slug}/tech-docs/`)
- `paths.trace_dir` → thư mục trạng thái trace; cấu trúc: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` (mỗi UC × platform một sổ)

Nếu không có section `paths`, dùng các giá trị mặc định:
- `specs_dir` = `specs`
- `refinement_dir` = `.agent/review`
- `qc_dir` = `docs`
- `qc_skills_dir` = `.agent/skills/qc`
- `product_definitions_dir` = `specs/product-definition`
- `domain_knowledge_dir` = `specs/domain-knowledge`
- `business_dictionary` = `specs/domain-knowledge/business-dictionary.md`
- `core_entities` = `specs/domain-knowledge/core-entities.md`
- `tech_docs_dir` = `specs`
- `trace_dir` = `.trace`

Lưu ý: Trong bố cục feature-package, `specs_dir` là gốc thống nhất. Mọi loại spec artifact (PRD, BDD, tech-docs, design-spec) đều nằm dưới `{specs_dir}/{domain}/{prd-slug}/`. `prd-slug` là tên folder feature-package, không phải một biến config riêng.

**Cách trích xuất `prd_slug` (đúng cho MỌI target file, bất kể độ sâu lồng nhau):** với một path target dạng `{specs_dir}/{domain}/{prd-slug}/...`, lấy **segment path đầu tiên sau `{specs_dir}/{domain}/`** — tức vị trí `{prd-slug}`. KHÔNG dùng folder cha trực tiếp của file, vì artifact BDD/tech-docs/design-spec lồng sâu hơn một hoặc hai cấp bên trong package. Ví dụ:
- `specs/payment/create-invoice/PAY01-create-invoice.md` → `prd_slug = create-invoice`
- `specs/payment/create-invoice/bdd/system/PAY-UC1.feature` → `prd_slug = create-invoice` *(KHÔNG phải `system`)*
- `specs/payment/create-invoice/bdd/web/PAY-UC1.feature` → `prd_slug = create-invoice` *(KHÔNG phải `web`)*
- `specs/payment/create-invoice/tech-docs/PAY01-tech-design.md` → `prd_slug = create-invoice` *(KHÔNG phải `tech-docs`)*
- `specs/payment/create-invoice/design-spec/PAY-design-spec-web.md` → `prd_slug = create-invoice`

Mọi artifact cùng cấp của một feature (PRD, BDD của từng platform, tech-docs BE + FE, design-spec, và trace TSV) đều phân giải về **cùng một `prd_slug`** — nên một BDD **system** hay tech-doc **system/BE** được tổng hợp sẽ nằm chung package `{specs_dir}/{domain}/{prd-slug}/` với các artifact web/app mà nó được suy ra từ đó.

Nếu `tech_stack.module` được đặt, đồng thời nạp `.agent/modules/{module}/stack-profile.yaml` nếu file tồn tại.

---

## Bước 1.5 — [SERVICE ROUTING] Phân giải path service (chế độ umbrella)

*Bỏ qua hoàn toàn bước này nếu `setup.mode` không phải `"umbrella"` và không có section `services` trong project-context.yaml.*

Nếu có section `services`:

**1. Phát hiện active domain** (theo thứ tự ưu tiên):
- Đọc `@trace.domain` từ frontmatter của target file (nếu Gate đã nạp một target file)
- Trích xuất từ path target file: `domain` = segment đầu tiên sau base path `specs_dir`; `prd_slug` = segment kế tiếp (folder feature-package). Điều này đúng ở mọi độ sâu target — xem quy tắc trích xuất `prd_slug` ở Bước 1.  
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
- Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`

**2. Route tới service** — nếu active domain khớp với một key trong `services`:
- Override `paths.specs_dir` → `services.{domain}.specs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) là artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
- Override `paths.tech_docs_dir` → `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract) là artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` — KHÔNG pin theo service ở đây.
- Lưu `active_service` = `services.{domain}.path`
- Lưu `active_service_module` = `services.{domain}.module`
- Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)

**3. Fallback** — nếu không phát hiện được domain hoặc không có service key khớp:
- Giữ path mặc định từ Bước 1
- Đặt `active_service = unresolved`

**4. Tự động override theo spec source** — nếu `setup.spec_source` được đặt VÀ path tương ứng chưa được set tường minh trong `paths:`:
- Override `paths.specs_dir` → `{spec_source}/specs` — **luôn khi `spec_source` được đặt.** Mọi spec artifact (PRD, BDD, tech-docs, design-spec) nằm dưới gốc spec thống nhất trong spec repo dùng chung theo bố cục feature-package: `{spec_source}/specs/{domain}/{prd-slug}/`. Mọi umbrella (FE/App/BE) đều đọc từ đây. *(`specs/` theo service chỉ khi không có `spec_source`.)*
- Override `paths.tech_docs_dir` → `{spec_source}/specs` — **luôn khi `spec_source` được đặt** (bước 2 không còn pin tech-docs theo service trong trường hợp này). Tech-docs nằm tại `{spec_source}/specs/{domain}/{prd-slug}/tech-docs/`. Tech-design CHÍNH LÀ API contract liên team: BE viết ở đây, FE/App đọc nó từ cùng spec submodule tại `/generate-code --phase=integration`. *(tech-docs theo service chỉ xảy ra khi không có `spec_source` — repo BE thuần đa-service không có spec module dùng chung.)*
- Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
- Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
- Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
- Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
- Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
- Override `paths.prd_change_requests_dir` → `{spec_source}/feedback/prd-change-requests`
- Override `paths.trace_dir` → `{spec_source}/.trace` — **luôn khi `spec_source` được đặt.** Trace TSV được gộp vào spec repo (một nơi authoritative duy nhất, không tách theo service) để PM/PO có một chỗ duy nhất quản lý trạng thái. Cấu trúc bên trong: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv`. Các lệnh phía code (`/generate-code`, `/dev-run-test`, `/qc-run-test`) chạy từ `service_root` nhưng **ghi trace row của chúng vào `{spec_source}/.trace/{domain}/{prd-slug}/`** — giống như chúng đã push `feedback/` vào đó. *(`.trace` theo service chỉ khi không có `spec_source`.)*
- Override `paths.refinement_dir` → `{spec_source}/.agent/review` — **luôn khi `spec_source` được đặt.** Findings review (`/refine-prd`, `/review-context`, `/review-tech-docs`) là artifact liên-team *về* tài liệu trong spec repo (PRD/BDD/tech-design) — thuộc cùng khu vực ghi với `.trace/` và `feedback/`. Các lệnh review chạy từ working dir của service (BE repo) nhưng **ghi findings vào `{spec_source}/.agent/review/`**, KHÔNG phải `.agent/review` của service repo. Bên trong flat, phân biệt bằng tên file đã prefix `{prd-slug}`/`{UC-ID}`/`{TICKET-ID}`. *(`.agent/review` theo service chỉ khi không có `spec_source`.)*

> **Vì sao đặt dưới `spec_source`:** PRD, BDD, tech-docs, design-spec, domain knowledge, feedback của tester, **trạng thái coverage `.trace/`**, **và findings review `.agent/review/`** đều là **artifact liên team** — chúng nằm trong **spec repo dùng chung** theo bố cục feature-package để mọi umbrella (FE/App/BE) và PM đọc từ một nguồn qua `/sync`. Trong bố cục feature-package, một folder `specs/{domain}/{prd-slug}/` gom tất cả loại artifact của một PRD, giúp spec repo tự đủ và dễ điều hướng theo feature. Service submodule chỉ chứa **code** (+ tooling build/test). `.trace/`, `.agent/review/` và `feedback/` là khu vực **ghi** của dev/QC/reviewer trong spec repo. Ở chế độ single-service (không có `spec_source`), mọi thứ mặc định dưới gốc repo — vẫn là một repo.

---

## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)

*Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*

Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):

**1. Định vị config của service** — thử theo thứ tự ưu tiên:
- `{active_service}/.agent/project-context.yaml`
- `{active_service}/project-context.yaml`

**2. Nếu tìm thấy, override bằng giá trị riêng của service:**

| Biến | Nguồn |
|----------|--------|
| `conventions.test_command` | `conventions.test_command` của service |
| `conventions.build_command` | `conventions.build_command` của service |
| `paths.trace_dir` | **Nếu `spec_source` được đặt → giữ route spec-repo của bước 4 (`{spec_source}/.trace`); bỏ qua mọi `trace_dir` cấp service.** Chỉ khi không có `spec_source`: `{active_service}/{service paths.trace_dir}` (mặc định `{active_service}/.trace`). |
| `paths.specs_dir` | **Nếu `spec_source` được đặt → giữ route spec-repo của bước 4 (`{spec_source}/specs`); bỏ qua mọi `specs_dir` cấp service** (mọi spec artifact đều liên team, không bao giờ theo service ở chế độ này). Chỉ khi không có `spec_source`: `{active_service}/{service paths.specs_dir}` nếu được set, else dùng override ở Bước 1.5. |
| `paths.refinement_dir` | **Nếu `spec_source` được đặt → giữ route spec-repo của bước 4 (`{spec_source}/.agent/review`); bỏ qua mọi `refinement_dir` cấp service** (findings review là artifact liên team). Chỉ khi không có `spec_source`: `{active_service}/.agent/review`. |

**3. Lưu** `service_root = {active_service}` làm mốc thư mục làm việc cho mọi lệnh phía sau:
- Các lệnh shell (`/dev-run-test`, `/dev-gen-test`) chạy **bên trong** `service_root`
- **File source/test** được ghi tương đối với `service_root`; **trace TSV** được ghi vào `{paths.trace_dir}` (là spec repo khi `spec_source` được đặt — một thao tác ghi liên-repo, commit/push vào spec submodule giống như `feedback/`).

**4. Nếu không tìm thấy config của service** — giữ mặc định umbrella, vẫn set `service_root = {active_service}` (luôn cần mốc path kể cả khi không có config override).

---

## Bước 2 — [PROJECT-CONFIG] Nạp module stack profile (có điều kiện)

Nếu `tech_stack.module` được đặt, đọc `.agent/modules/{module}/stack-profile.yaml`.
Merge các convention riêng của framework (layer pattern, test pattern, quy tắc đặt tên) vào context đã nạp.
Nếu file không tồn tại → bỏ qua âm thầm.

---

## Bước 3 — [CRITICAL] Nạp CLAUDE.md (phân tầng: root + service overlay)

*Đây là context ưu tiên cao nhất — nó định nghĩa CÁCH viết code và tài liệu cho dự án này.*

CLAUDE.md được nạp theo **hai tầng** để các quy tắc toàn-umbrella và kiến trúc/coding standards
riêng của service kết hợp đúng cách. Agent luôn đứng ở gốc umbrella, nhưng code triển khai nằm
trong một service submodule với stack, kiến trúc, và convention RIÊNG của nó — nên CLAUDE.md của
service phải thắng khi sinh code.

**Tầng 1 — [BASE] Root CLAUDE.md (toàn umbrella).**
Đọc `CLAUDE.md` ở gốc repo. Coi nội dung của nó là **nền tảng dùng chung** cho cả umbrella —
git convention, tư thế bảo vệ dữ liệu, quy tắc xuyên suốt, và (ở chế độ single-service) là
kiến trúc + coding standards duy nhất của dự án.

**Tầng 2 — [OVERLAY] Service CLAUDE.md (chỉ chế độ umbrella).**
*Chỉ chạy nếu `service_root` đã được set ở Bước 1.6 (tức đã route tới một service thật).*
Đọc `{service_root}/CLAUDE.md`. File này định nghĩa kiến trúc + coding standards của **stack
thực sự đang được triển khai** (vd: `user-service` = java-spring, `web` = nextjs).
Overlay nó lên trên Tầng 1: **khi có xung đột, giá trị của service THẮNG** cho kiến trúc,
coding standards, và error handling. Các giá trị Tầng 1 mà service không định nghĩa lại
(vd: git convention, banned pattern dùng chung toàn tổ chức) vẫn có hiệu lực.

Từ kết quả **đã merge**, trích xuất và lưu:

- **§1 Project Overview** → tên dự án, ngôn ngữ, framework, lệnh build/test, domains
- **§2 Architecture** → thứ tự layer (vd: Controller → Facade → Service → Repository), quy tắc kiến trúc — *service overlay thắng*
- **§2 Package Layout** → **base package** (vd `vn.edupia.{service}`) + **chiến lược đặt package** (by-layer / by-feature) + nơi code một domain sống. Đây là **quy ước đặt code trên đĩa**, PHẢI enforce khi sinh code. Nếu §2 chỉ nêu base package + thứ tự layer mà **không** nói tới sub-package theo feature → hiểu là **by-layer**: các layer đặt **TRỰC TIẾP** dưới base package (vd `vn.edupia.{service}.service`, `.repository`); feature/UC/prd-slug **KHÔNG** thành sub-package, chỉ phân biệt ở **tên class**. Lưu `code_base_package` + `package_strategy` — *service overlay thắng*.
- **§3 Coding Standards** → quy tắc đặt tên (class, method), kiểu response wrapper, pattern bị cấm — *service overlay thắng*
- **§5 Error Handling** → kiểu exception, mapping HTTP status code, tên class not-found exception — *service overlay thắng*
- **§7 Git Conventions** → pattern đặt tên branch, format commit message — *lấy theo root trừ khi service định nghĩa lại*

**Quy tắc phân giải:**
- Nếu cả hai tầng tồn tại → merge như trên; ghi `claude_md_source = root + {service_root}`.
- Nếu chỉ có service overlay (không có root CLAUDE.md) → dùng file service một mình; `claude_md_source = {service_root}`.
- Nếu `service_root` được set nhưng `{service_root}/CLAUDE.md` **thiếu** → fallback về root CLAUDE.md và gắn cờ ⚠️ trong recap Bước 7 (service không có định nghĩa kiến trúc/coding-standards — việc sinh code sẽ dùng mặc định umbrella, có thể sai stack).
- Nếu cả hai đều không tồn tại → ghi nhận CLAUDE.md thiếu và tiếp tục chỉ với dữ liệu từ project-context.yaml.

---

## Bước 4 — [SAFETY] Nạp quy tắc bảo vệ dữ liệu

Đọc `.agent/rules/data-protection.md` (hoặc `rules/data-protection.md` từ bản cài đặt framework).

Lưu các pattern file nhạy cảm — bạn **tuyệt đối không** đọc, ghi, hiển thị, hay tham chiếu nội dung từ các file khớp những pattern đó trong suốt cả phiên.

Nếu cả hai file đều không tồn tại → áp dụng mặc định built-in: không bao giờ truy cập `.env*`, `*.key`, `*.pem`, `*secret*`, `*password*`, `*credential*`.

---

## Bước 5 — [DOMAIN] Nạp Business Dictionary (có điều kiện)

Kiểm tra file business dictionary có tồn tại không (dùng `paths.business_dictionary` đã phân giải ở Bước 1).

Nếu tồn tại, đọc và trích xuất:
- **Canonical Terms** → danh sách đầy đủ các thuật ngữ chuẩn và định nghĩa
- **Banned Terms** → danh sách đầy đủ các thuật ngữ bị cấm và bản thay thế chuẩn
- **Status / Enum Registry** → các giá trị enum được phép theo từng entity

Lưu danh sách banned term để **thực thi chủ động** suốt phiên làm việc của lệnh:
- Khi sinh bất kỳ văn bản nào (PRD, BDD, comment code, tech docs), kiểm tra không có banned term nào xuất hiện
- Tự động thay banned term bằng bản chuẩn tương đương

Nếu file không tồn tại → bỏ qua âm thầm. Không cảnh báo hay chặn.

---

## Bước 6 — [DOMAIN] Nạp Core Entities (có điều kiện)

Kiểm tra file core entities có tồn tại tại `paths.core_entities` không (đã phân giải ở Bước 1).
Path mặc định: `specs/domain-knowledge/core-entities.md`.

Nếu tồn tại, đọc và lưu:
- **Entity catalog** → với mỗi entity: tên, mục đích, service sở hữu, các field chính (tên + kiểu), business invariant, và quan hệ
- **Field name registry** → tên field chuẩn dùng trong code và tài liệu được sinh ra
- **Relationship map** → cách các entity liên hệ với nhau (1:N, N:N, embedded, v.v.)

**Cách dùng catalog này:**
- Khi sinh code: dùng tên field, kiểu, và quan hệ định nghĩa ở đây — KHÔNG suy đoán từ code có sẵn
- Khi sinh PRD/BDD: tham chiếu tên entity từ catalog này để nhất quán
- Khi sinh tech-docs: dùng catalog này làm nguồn chân lý cho định nghĩa entity

Nếu file không tồn tại → bỏ qua âm thầm.

---

## Bước 6.5 — [PLATFORM] Suy ra active_module và platform_type

Dùng `tech_stack.module` đã nạp ở Bước 1, suy ra và lưu hai biến để mọi lệnh phía sau dùng:

```
active_module = tech_stack.module   (vd: "java-spring", "react", "flutter")
```

| `platform_type` | Modules |
|---|---|
| `backend` | `java-spring`, `golang`, `dotnet`, `php-laravel`, `context-engineering` |
| `web-frontend` | `react`, `nextjs`, `vue`, `nuxt`, `angular` |
| `mobile` | `flutter`, `react-native`, `ios-swiftui`, `android-compose` |

Nếu `tech_stack.module` rỗng hoặc không nhận diện được → set `platform_type = "unknown"` và gắn cờ ⚠️ trong recap Bước 7.

Hai biến này (`active_module`, `platform_type`) là nguồn chuẩn cho mọi logic rẽ nhánh trong các lệnh cần hành vi riêng theo platform (dev-gen-test, debug, fix-bug, dev-smoke-test).

---

## Bước 6.7 — [GUARDRAILS] Nạp Project Lessons (có điều kiện)

*Các lỗi tích luỹ mà AI không được lặp lại trong dự án này. Chúng được bổ sung dần qua `/learn`
hoặc được chấp nhận trong `/review-code`, `/fix-bug`, `/debug`.*

Phân giải path file lessons:
- Dùng `paths.lessons_file` nếu được set (có thể bị service override ở chế độ umbrella, Bước 1.6)
- Else mặc định `specs/domain-knowledge/lessons-learned.md`
- Ở chế độ umbrella/service (khi `service_root` được set), nếu `paths.lessons_file` chưa set, mặc định `{service_root}/.agent/project-lessons.md`

Nếu file tồn tại, đọc và lưu TẤT CẢ lesson làm **GUARDRAIL ĐANG HOẠT ĐỘNG** cho phiên:
- Coi **Rule** của mỗi lesson là ràng buộc cứng — cùng mức ưu tiên với coding standards trong CLAUDE.md (Bước 3).
- Trước khi sinh hoặc sửa bất kỳ artifact nào (PRD, BDD, tech-doc, code, test), đối chiếu output với mọi lesson có `category` khớp lệnh hiện tại VÀ `scope` khớp target (domain / file).
- Nếu output sinh ra vi phạm một lesson → sửa **trước khi** trình bày, và ghi rõ lesson nào (`L-NNN`) đã được áp dụng.

Nếu file không tồn tại → bỏ qua âm thầm (chưa có lesson nào được ghi nhận).

---

## Bước 7 — [RECAP] Working Memory Recap (chống lost-in-middle)

Sau khi nạp toàn bộ context, tổng hợp và xuất một khối tóm tắt gọn.
Recap này đảm bảo các sự thật quan trọng nhất được nêu ở CUỐI quá trình nạp context
(hiệu ứng recency — tươi mới nhất trong bộ nhớ làm việc khi bắt đầu task).

Xuất đúng khối này:
```
[CTX LOADED]
Stack     : {language} / {framework} / {database}
Platform  : {active_module} ({platform_type})
Layers    : {thứ tự layer từ CLAUDE.md §2 đã merge, vd: Controller → Facade → Service → Repository}
Package   : {code_base_package}.{layer} · {by-layer | by-feature}  ← feature/UC → tên class, KHÔNG thành package (nếu by-layer)
CLAUDE.md : {root + {service_root} | chỉ {service_root} | chỉ root | ⚠️ service overlay THIẾU — dùng root | missing}
Ticket    : {ticket_prefix}-
Dict      : {loaded — N canonical terms, M banned terms | missing}
Entities  : {loaded — EntityA, EntityB, EntityC | missing}
Lessons   : {loaded — N guardrails | chưa có}
Service   : {active_service} ({active_service_module}) | single-service
Svc Root  : {service_root} — đã nạp conventions + trace_dir từ config service | —
Status    : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
```

Nếu bất kỳ file CRITICAL nào thiếu (CLAUDE.md), gắn cờ rõ ràng để người dùng quyết định có tiếp tục hay không.

---

## Hoàn tất nạp Context

Sau khi hoàn thành tất cả các bước, bạn đã nạp:
- Định danh dự án, tech stack, convention module
- Quy tắc kiến trúc và thứ tự layer  ← **[CRITICAL — giữ trong bộ nhớ làm việc]**
- Coding standards và quy tắc đặt tên  ← **[CRITICAL — giữ trong bộ nhớ làm việc]**
- Quy tắc bảo vệ dữ liệu (pattern file nhạy cảm không bao giờ truy cập)
- Quy tắc thuật ngữ kèm danh sách banned term  ← **[DOMAIN — áp dụng cho mọi từ được sinh ra]**
- Entity catalog (tên field, kiểu, invariant)  ← **[DOMAIN — dùng khi sinh code]**
- Toàn bộ path đã cấu hình

Tiếp tục sang bước kế tiếp của lệnh đang gọi.


> **Proposal của tester (input tuỳ chọn):** trước khi sinh, quét `{paths.bdd_proposals_dir}/` (mặc định `{spec_source}/feedback/bdd-proposals/`) tìm `{UC-ID}-*.md`. Với mỗi proposal:
> - `Status: accepted` (PO/Dev đã duyệt) → chèn scenario vào `.feature` của UC (giữ `@trace`), rồi **lưu trữ**: chuyển file sang `{paths.bdd_proposals_dir}/archived/` + đặt `Status: incorporated`, và **commit + push** spec repo để gỡ khỏi feedback chung.
> - `Status: proposed`/`rejected` (hoặc thiếu `Status`) → **bỏ qua**, để nguyên cho PO/Dev xử lý (KHÔNG tự đoán, KHÔNG tự đưa vào).
> Bỏ qua sạch nếu folder rỗng.

---

## Sub-Agent Mode — dùng state từ payload *(nếu `_agent_mode`)*

*Chỉ khi Gate Step 0 phát hiện `_agent_mode: true` (đang chạy như sub-agent do orchestration spawn).* Orchestrator (session chính) đã chạy các Guard + chọn platform + nạp design-spec **một lần**; sub-agent KHÔNG lặp lại:
- `active_platform` = `payload.active_platform` → **bỏ qua** Platform Selection / Service Detection.
- `design_coverage` = `payload.design_coverage` → **bỏ qua** "Design Spec — Gate & Load"; nếu rỗng thì chỉ phủ Wireframe PRD.
- **Bỏ qua** Guard "PRD đã duyệt" + Guard Design-Spec bên dưới (orchestrator đã kiểm).
- Đi thẳng tới UC Decomposition + Generate cho `payload.uc_id`, dùng `design_coverage` để phủ Screen States + AC-UI.

---

## Guard — PRD đã duyệt chưa

Đọc `| **Status** |` từ bảng Metadata của PRD nguồn:
- `Status: approved` → tiếp tục bình thường.
- `Status: draft` (hoặc khác `approved`) → **CHECKPOINT cảnh báo mềm** (không chặn cứng — cho phép prototype):
  ```
  ⚠️  PRD đang ở Status: {status} (chưa duyệt). BDD sinh từ PRD chưa chốt có thể phải làm lại.
     Khuyến nghị: PO review xong đặt `| **Status** | approved |` rồi mới sinh BDD.
     Vẫn sinh BDD bây giờ? (Y/N)
  ```
  Chỉ tiếp tục khi người dùng chọn Y.

---

## Phát hiện Repo Mode

Sau khi nạp context, xác định chế độ hoạt động:

- **Spec repo mode**: `project-context.yaml` KHÔNG có section `services` HOẶC `setup.mode: spec`
- **Umbrella mode**: `project-context.yaml` CÓ section `services` VÀ `setup.mode: umbrella`

→ Spec repo mode → tới **Platform Selection** bên dưới (bỏ qua Service Detection)
→ Umbrella mode → tới **Service Detection** bên dưới (bỏ qua Platform Selection)

---

## Platform Selection (chỉ Spec Repo Mode)

*Bỏ qua section này nếu đang chạy umbrella mode.*

Hỏi người dùng chọn platform target:

```
BDD này dành cho platform nào?
  1. web    — FE/Web (React, Next.js, Angular, Vue, Nuxt)
  2. app    — Mobile (Flutter, React Native, iOS, Android)
  3. system — System/BE BDD (tổng hợp từ web + app BDD có sẵn)
```

Chờ người dùng chọn. Set `active_platform` = giá trị đã chọn.

**Output path (spec repo mode):**
`{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC{N}-{slug}.feature`

**Từ vựng theo platform:**

| Platform | "user action" | "type/input" | "observe" | "navigate" |
|---|---|---|---|---|
| web | "clicks" | "types into" / "enters" | "sees" / "the page shows" | "navigates to" / "goes to" |
| app | "taps" | "enters" / "inputs" | "sees" / "the screen shows" | "navigates to" / "opens" |
| system | N/A — dùng business event | — | "the system returns" / "receives response" | — |

---

## System BDD Synthesis (active_platform = system)

*Chỉ áp dụng khi platform = system. Bỏ qua với web và app.*

### Step S0 — Brownfield Check

Kiểm tra bảng Metadata của PRD nguồn tìm `| **API Source** | existing |`.

**Nếu `API Source: existing`:**
- API contract đã được PO ghi trong phần "Existing API Contract" của PRD.
- **Skip Steps S1–S3** — không cần scan FE/App BDD, không cần conflict resolution.
- Dùng bảng "Existing API Contract" trong PRD làm contract input cho Step S4.
- Set `# @trace.api_source: existing` trong header của file system BDD được gen.

**Nếu `API Source` không có hoặc không phải `existing`:**
- Tiếp tục Steps S1–S3 (normal synthesis flow).

---

### Step S1 — Scan các BDD FE/App có sẵn

Tìm các BDD có sẵn cho TICKET-ID này:
- Web BDD: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/web/{TICKET-ID}-*.feature`
- App BDD: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/app/{TICKET-ID}-*.feature`

Phân loại feature:

| Điều kiện | Mode |
|---|---|
| Tìm thấy cả web + app BDD | **Multi-platform** — tổng hợp từ cả hai |
| Chỉ tìm thấy web BDD | **Web-only** — tổng hợp từ web |
| Chỉ tìm thấy app BDD | **App-only** — tổng hợp từ app |
| Không tìm thấy FE/App BDD | **Backend-only** — gen trực tiếp từ PRD |

---

### Step S2 — Trích contract kỳ vọng theo từng platform

Với mỗi file BDD tìm thấy, trích:
- **Triggers**: hành động người dùng nào gọi backend? (map sang event "request" logic)
- **Expected response data**: mỗi mệnh đề `Then` cần field/shape gì từ hệ thống?
- **Error signals**: backend phải báo hiệu các trạng thái lỗi nào?
- **Business rules**: mỗi platform giả định hệ thống thực thi các invariant nào?

---

### Step S3 — Cross-Platform Conflict Check (chỉ multi-platform mode)

*Bỏ qua nếu web-only, app-only, hoặc backend-only.*

So sánh các contract đã trích giữa các platform. Gắn cờ conflict nếu bất kỳ cái nào khác nhau:

| Loại conflict | Ví dụ |
|---|---|
| **Response shape mismatch** | Web mong `{ token, redirect_url }`, App mong `{ token, user_profile }` |
| **Error semantics mismatch** | Web mong HTTP 423 cho lock, App mong custom error code `ACC_LOCKED` |
| **Business rule contradiction** | Web BDD nói "lock sau 5 lần", App BDD nói "lock sau 3 lần" |
| **Data field conflict** | Web mong `expires_in: seconds`, App mong `expires_at: ISO timestamp` |

**Nếu phát hiện conflict → CHECKPOINT (bắt buộc, không bỏ qua được):**

```
⚠️  CROSS-PLATFORM CONTRACT CONFLICT
──────────────────────────────────────────────────────────────────
Feature : {TICKET-ID} — {UC name}

Conflict 1: Response shape mismatch
  Web BDD (Then): user sees dashboard → implies { token, redirect_url }
  App BDD (Then): app navigates to HomeScreen → implies { token, user_profile }

Resolution options:
  A — Union response
      BE trả về tất cả field: { token, redirect_url, user_profile }
      Client bỏ qua field không dùng. Đơn giản, hơi over-fetch.
  B — Platform hint trong request
      Client gửi X-Platform: web|app trong header, BE tuỳ biến response.
      Response gọn hơn, nhiều BE logic hơn.
  C — Endpoint riêng
      POST /auth/login/web  và  POST /auth/login/app
      Linh hoạt tối đa, nhiều endpoint phải bảo trì hơn.
  D — Custom: mô tả cách của bạn
──────────────────────────────────────────────────────────────────
Chọn resolution cho mỗi conflict (A/B/C/D):
```

Chờ PO giải quyết từng conflict. Ghi mỗi quyết định thành annotation `# @system.resolution:` trong file system BDD được gen.

**Nếu không có conflict → tới Step S4 trực tiếp.**

---

### Step S4 — Sinh các scenario System BDD

Sinh scenario dựa trên mode và các conflict đã giải quyết:

- **Multi-platform**: tổng hợp từ cả contract web + app, áp dụng các resolution đã chọn
- **Web-only / App-only**: suy ra từ contract của một platform
- **Backend-only**: suy ra trực tiếp từ AC/BR của PRD dùng ngôn ngữ business event (không phải HTTP)

Từ vựng step của System BDD (luôn dùng — bất kể từ vựng FE/App):
- Triggers: "the system receives {event}" / "a {actor} submits {action}"
- Assertions: "the system returns {data}" / "the system signals {error}" / "the system stores {state}"
- KHÔNG dùng từ UI (click, tap, see, navigate) trong system BDD

**Nếu multi-platform với resolution A (union):**
- System BDD thể hiện contract response đầy đủ: tất cả field từ mọi platform
- Thêm comment: `# @system.resolution: union — clients receive all fields`

**Nếu resolution B (platform hint):**
- Viết `Scenario Outline` riêng dùng Examples table cho biến thể response `web` vs `app`
- Thêm comment: `# @system.resolution: platform-hint — X-Platform header determines response shape`

**Nếu resolution C (endpoint riêng):**
- Viết Scenario riêng cho mỗi endpoint
- Ghi rõ việc tách endpoint trong phần SCOPE

---

## Service Detection (chỉ Umbrella Mode)

*Bỏ qua section này nếu đang chạy spec repo mode.*

Routing service là **domain-keyed** và **context-loader (Bước 1.5) đã phân giải sẵn** từ `@trace.domain`/Domain của PRD — KHÔNG re-resolve ở đây, chỉ dùng lại các biến đã set:
- `active_service` = `services.{domain}.path` (path submodule, vd `user-service/`) — hoặc `"unresolved"` nếu domain không khớp entry nào, hoặc bỏ trống ở single-service.
- `active_module` = module của service (`services.{domain}.module`, đã override `tech_stack.module` ở Bước 1.5) — dùng cho từ vựng bên dưới.

Chỉ cần kiểm tra trạng thái đã phân giải:

| Trạng thái (từ context-loader) | Hành động |
|---|---|
| `active_service` đã phân giải thành path service | Tiếp tục với `active_module` đã set. |
| `active_service = "unresolved"` (có section `services` nhưng domain PRD không khớp entry nào) | **DỪNG**, báo: "Domain `{domain}` của PRD không khớp service nào trong `services:` của project-context.yaml — bổ sung mapping rồi chạy lại." (Không đoán/hỏi tay — domain là khoá định danh, lệch là lỗi cấu hình cần sửa ở SoT.) |
| Single-service (không có section `services`) | `active_module = tech_stack.module` (đã set ở Bước 6.5). Tiếp tục. |

**Output path (umbrella mode):** `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC{N}-{slug}.feature`

*(Không thêm subfolder theo service: feature-package đã domain-scoped sẵn ở `{domain}/`, mà service route 1-1 theo domain — nên thêm subfolder service sẽ chỉ lặp lại domain. `active_service` chỉ dùng cho `service_root`/từ vựng, KHÔNG vào path spec.)*

**Từ vựng theo platform** — điều chỉnh cách viết step BDD theo `active_module`:

| Platform type | Modules | "click" | "type" | "see" | "navigate" |
|---|---|---|---|---|---|
| Web | react, nextjs, vue, nuxt, angular | "clicks" | "types into" / "enters" | "sees" / "the page shows" | "navigates to" / "goes to" |
| Mobile | flutter, react-native, ios-swiftui, android-compose | "taps" | "enters" / "inputs" | "sees" / "the screen shows" | "navigates to" / "opens" |
| Backend / API | java-spring, golang, dotnet, php-laravel | *(không có UI step — dùng)* "submits a request" / "calls the API" | — | "receives response" / "the system returns" | — |

Áp dụng từ vựng này âm thầm khi viết step Gherkin. KHÔNG trộn từ web và mobile trong cùng một file feature.

---

## Design Spec — Gate & Load (chỉ FE/App)

*Chỉ chạy khi target platform là FE/App — spec mode: `active_platform ∈ {web, app, app-ios, app-android}`; umbrella mode: `active_module` là module FE/App (react/nextjs/vue/nuxt/angular/flutter/react-native/ios-swiftui/android-compose). Bỏ qua HOÀN TOÀN với `system` và backend/brownfield.*

**1. Định vị design-spec của platform:**
`{paths.specs_dir}/{domain}/{prd-slug}/design-spec/{TICKET-ID}-design-spec-{active_platform}-{slug}.md`
- `app-ios`/`app-android` không có bản riêng → fallback bản `-app-`.

**2. Guard — sign-off & độ tươi (cảnh báo MỀM, đồng bộ Guard PRD — không chặn cứng):**
Đọc `| **Status** |` và `| **Built from PRD** |` từ Metadata design-spec.
- Không tìm thấy file, HOẶC `Status ≠ approved`, HOẶC design-spec còn màn ❌ Missing, HOẶC `Built from PRD` ≠ `| **Version** |` của PRD hiện tại (design-spec **lỗi thời** so với PRD) → CHECKPOINT:
  ```
  ⚠️  Design Spec cho {active_platform} chưa sẵn sàng (Status: {status} / không có / còn màn thiếu Figma / lỗi thời: dựng từ PRD v{old}, PRD giờ v{new}).
     BDD FE/App nên sinh từ design-spec đã approved & cập nhật để phủ đúng Screen States + AC-UI.
     Khuyến nghị: hoàn tất / cập nhật design-spec (chạy lại /generate-design-spec nếu PRD đã đổi) rồi mới sinh BDD.
     Vẫn sinh BDD bây giờ? (Y/N)
  ```
  Chỉ tiếp khi chọn Y. Nếu Y mà KHÔNG có design-spec → bỏ qua bước 3 (chỉ phủ Wireframe PRD §4b).
- `Status: approved` VÀ `Built from PRD` khớp PRD hiện tại → nạp design-spec, sang bước 2.5.

**2.5. Sanity-scan nội dung design-spec** (lớp soi độc lập — D1; soi nhanh ngay tại chỗ đã mở file, trước khi dùng):
Quét tìm cờ đỏ; nếu có → **cảnh báo mềm** (liệt kê + hỏi "Vẫn dùng design-spec này? (Y/N)"):
- Màn nào thiếu state `loading`/`error`/`empty`.
- AC-UI nào mơ hồ, không testable ("looks good" / "đẹp" / không pass-fail rõ).
- Component còn `[NEW]` / `[TODO]` (chưa chốt với designer).
- Còn `❌ Missing` frame (lẽ ra Status đã `draft` — approved mà vẫn Missing là bất thường).
Bắt lỗi design-spec **ngay trước khi nó lan xuống BDD**. Chọn N → quay lại hoàn thiện design-spec; chọn Y → sang bước 3.

**3. Trích coverage từ design-spec** (lưu thành `design_coverage`, dùng ở UC Decomposition + Coverage Matrix):
- **Screen States** ≠ `default` cho mỗi màn: `loading`, `error`, `empty`, `success` (cái nào có).
- **AC-UI behavioral**: giữ AC-UI mà cột `Verified by` là **PO/QA** và mô tả outcome quan sát được (lỗi + đường khôi phục, empty state + CTA, gesture điều hướng, có loading state). **LOẠI AC-UI visual thuần** (khớp Figma trong dung sai, tương phản WCAG, màu/pixel/animation — thường `Verified by: Designer`): Designer/QA review riêng, KHÔNG đưa vào Gherkin (giữ R3/R5/R6).
- **Dedup**: nếu một Screen State / AC-UI đã trùng một AC nghiệp vụ của PRD → không tạo SC mới, chỉ ghi nhận đã phủ.

---

## Orchestration Check

*Bỏ qua section này nếu đã ở sub-agent mode (Step 0 của Gate đã kích hoạt).*

Sau khi nạp context, kiểm tra PRD target có đủ lớn để cần sub-agent không:

1. Đếm các heading `#### {TICKET-ID}-UC` trong PRD → **UC count**.
2. Đếm tổng số dòng trong PRD → **line count**.
3. Nếu **UC count > 3** HOẶC **line count > 300**:
   - Chuyển sang orchestration mode — theo `steps/spawn-agent.md`.
   - Session chính trở thành orchestrator: spawn 1 sub-agent cho mỗi UC.
   - Mỗi sub-agent chạy `/generate-bdd` với payload `_agent_mode: true`.
   - Thu thập kết quả và hiện report đã merge.
   - **KHÔNG tiếp tục các bước bên dưới.**
4. Nếu UC count ≤ 3 VÀ line count ≤ 300 → tiếp tục Version Check bên dưới (single-session mode).

---

## Sub-Agent Return Format

*Section này áp dụng khi chạy như sub-agent (Gate Step 0 phát hiện `_agent_mode: true`).*

Sau khi sinh tất cả file `.feature` và `.tsv` cho UC được giao, trả về JSON kết quả có cấu trúc (theo `steps/spawn-agent.md` Step E):

```json
{ "uc_id": "{TICKET-ID}-UC{N}", "files_created": ["path/to/file1", "path/to/file2"], "status": "success | error", "errors": [] }
```

---

## Version Check

Trước khi sinh, kiểm tra các file `.feature` có sẵn cho PRD này:

1. Phân giải search path theo mode:
   - **Spec repo mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC*.feature`
   - **Umbrella mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC*.feature`
2. Đọc `| **Version** |` hiện tại của PRD từ metadata (vd: `1.2`).

**Nếu không có file feature nào** → gen mới, tiếp tục bình thường. Dùng version PRD làm `@trace.prd_version`.

**Nếu tìm thấy file feature có sẵn**:
- Đọc `# @trace.prd_version:` từ header file feature có sẵn.
- So với version PRD hiện tại.
- Nếu **giống** → hỏi: "BDD đã sinh từ PRD v{version}. Gen lại? (Y/N)"
- Nếu **khác** (PRD đã cập nhật):
  1. Đọc `# Change Log` từ PRD — trích tất cả row mới hơn `@trace.prd_version` của BDD hiện có. **Nếu `@trace.prd_version` của BDD CŨ HƠN row cũ nhất còn trong bảng** (lịch sử đã bị cắt sang `changelog/`) → không thấy đủ diff → **khuyến nghị F** (gen lại toàn bộ), đừng tin Y một phần.
  2. Hiện CHECKPOINT:
     ```
     ⚠️  Phát hiện PRD version drift
     BDD được sinh từ PRD v{old}
     PRD giờ ở v{new}

     Thay đổi kể từ v{old}:
       {changelog rows}

     Options:
       Y — chỉ cập nhật các scenario bị ảnh hưởng
       F — gen lại toàn bộ scenario
       N — huỷ
     ```
  3. Tiếp tục theo lựa chọn của người dùng. **Nếu changelog row không nêu rõ UC/AC/BR bị đổi (mơ hồ) → khuyến nghị F** (gen lại toàn bộ) thay vì Y, để khỏi sót scenario bị ảnh hưởng (lưới an toàn — không chắc đổi ở đâu thì quét rộng).

---

## BDD Writing Rules (R1-R10 — enforce nghiêm)

| Rule | Name | Yêu cầu |
|------|------|-------------|
| R1 | Given/When/Then Semantics | Given=state, When=action, Then=outcome. Mỗi SC cần đủ G/W/T. |
| R2 | One Behavior Per Scenario | 1 SC = 1 behavior. KHÔNG chain When→Then→When→Then. |
| R3 | Ubiquitous Language | KHÔNG dùng UI selector / tên API / tech term trong step. |
| R4 | Outside-in Naming | Tên SC mô tả business outcome. Không "click" / "(Case X)" / tên component. |
| R5 | Declarative over Imperative | Mô tả WHAT (ý định nghiệp vụ), KHÔNG phải HOW (cơ chế UI). |
| R6 | Observable Outcomes Only | Then khẳng định outcome quan sát được. Không phải trạng thái UI trung gian / internal state. |
| R7 | Key Examples / Concrete | Dùng giá trị cụ thể. Không "valid data" mơ hồ. |
| R8 | Independence | SC chạy độc lập. Không phụ thuộc state từ SC khác. |
| R9 | Test Data Completeness | Data table có đủ field để suy ra Then kỳ vọng. |
| R10 | Scope Boundary Explicit | Cross-UC reference dùng cách diễn đạt navigation + comment Note. |

## Project Compliance (fail review nếu thiếu — C.1-C.5)

| Check | Rule |
|-------|------|
| C.1 Wireframe Coverage | Mỗi component/action trong Wireframe (PRD §4b) có ≥1 SC. **FE/App: mỗi Screen State (≠default) và mỗi AC-UI behavioral của design-spec (`design_coverage`) cũng phải có ≥1 SC** — dedup với AC nghiệp vụ PRD; bỏ AC-UI visual thuần. |
| C.2 PRD Traceability | Mỗi AC và mỗi BR (gồm từng bullet logic) map tới ≥1 SC. |
| C.3 Business Dictionary | Dùng đúng canonical term từ business-dictionary.md. |
| C.4 Banned Terms | 0 banned term trong file — grep trước khi gen. |
| C.5 NHÓM Grouping | Feature ≥3 SC → PHẢI có NHÓM grouping theo business theme. |

---

## NHÓM Grouping Convention (C.5 — bắt buộc cho ≥3 scenario)

Gom theo business theme, KHÔNG theo happy/negative/edge.

Format header (thụt 2 space, cùng cấp với Background):
```
  # ==========================================================
  # NHÓM N: <Business theme> (<BR refs nếu áp dụng>)
  # ==========================================================
```

Rules:
- Đánh số tuần tự NHÓM 1 → N. SC ID tuần tự xuyên suốt lifecycle (không reset theo từng NHÓM).
- Mỗi NHÓM có thể chứa @happy + @edge + @negative cùng theme.
- SC trong NHÓM không cần theo thứ tự ID (NHÓM 2 có thể chứa SC4, SC8, SC11 nếu cùng theme).

Pattern gợi ý (điều chỉnh theo UC):
- `Init / Save success — valid data combinations`
- `Validation / Block when invalid`
- `Error handling — API fail / system error`
- `Cancel changes / Close modal without saving`
- `Cross-system / Downstream effects`
- `Idempotency & Concurrency`

---

## UC Decomposition

Với mỗi UC trong PRD, trình bày outline SC **trước khi sinh**:
```
{TICKET-ID}-UC1: {Use Case Name}
  NHÓM 1: {Theme} (BR1, BR2)
    SC1 [@happy]:              {business outcome}
    SC2 [@happy @alternative]: {variant outcome}
  NHÓM 2: {Theme} (BR2, BR3)
    SC3 [@edge]:               {edge case}
    SC4 [@negative]:           {error handling}
  ACs covered: AC1, AC2
  BRs covered: {TICKET-ID}-UC1-BR1, BR2, BR3
```

*(FE/App: nếu đã nạp design-spec (xem "Design Spec — Gate & Load"), đưa Screen State ≠default (loading/error/empty) + AC-UI behavioral của `design_coverage` vào outline — dedup với AC nghiệp vụ, đừng tạo SC trùng.)*

CHECKPOINT: "Outline này đúng chưa? Bạn muốn thêm hay bớt SC nào không?" → **Chờ confirm trước khi sinh.**

---

## Generate

**Output path theo mode:**
- **Spec repo mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC{N}-{slug}.feature`
- **Umbrella mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC{N}-{slug}.feature` *(service route 1-1 theo domain → không thêm subfolder service)*

Với mỗi UC, ghi vào path đã phân giải ở trên. Dùng từ vựng cho active platform (từ Platform Selection hoặc Service Detection).

```gherkin
# ============================================================
# @trace.id: {TICKET-ID}-UC{N}
# @trace.title: <Feature name>
# @trace.revision: 1  ← field tĩnh; dùng @trace.bdd_version để theo dõi version (tăng bởi /review-context --fix hoặc --resume)
# @trace.domain: <domain>
# @trace.platform: {active_platform — web | app | system | (bỏ trong umbrella mode)}
# @trace.service: {active_service — bỏ trong spec repo mode}
# @trace.module: {active_module trong umbrella mode; "unknown" trong spec repo mode}
# @trace.status: draft
# @trace.author: AI-generated
# @trace.created_at: {YYYY-MM-DD}
# @trace.prd: {TICKET-ID}
# @trace.prd_version: {đọc từ metadata PRD "| **Version** |"}
# @trace.bdd_version: {1.0 nếu gen mới; tăng 0.1 khi gen lại — vd 1.0 → 1.1}
# @trace.business_rules: {TICKET-ID}-UC{N}-BR1, {TICKET-ID}-UC{N}-BR2
# @trace.dataset: {domain}.testdata.yaml
# ============================================================

# === CONTEXT ===
# Actor:     <vai trò thực hiện hành động, vd: Consumer, Staff, System>
# Screens:   <các màn liên quan, vd: Cart → Confirm Order → Order Detail>
# Entities:  <business entity, vd: Order, OrderItem, Consumer>
# Pre-state: <state dùng chung trước khi vào các scenario>

# === SCOPE ===
# In:  <UC này phủ gì>
# Out: <cái gì KHÔNG thuộc UC này — link tới UC/feature khác (R10)>

# === BUSINESS DEFINITION ===
# Tham chiếu nhanh các term dùng trong feature này. Chi tiết SoT: business-dictionary.md
# <Term 1>: <định nghĩa ngắn>
# <Term 2>: <định nghĩa ngắn>
#
# --- Popup/Modal Lifecycle (tùy chọn — BẮT BUỘC nếu feature là popup/modal; Pre-merge yêu cầu) ---
# - Open trigger:   <khi nào popup hiển thị, vd: click menu sidebar>
# - Close trigger:  <khi nào popup đóng, vd: F5 / click X / ESC / navigate away>
# - Refresh model:  <data refresh khi nào, vd: mỗi lần open (NO CACHE) / persisted / polling>
# - State reset:    <state nào reset khi đóng/mở lại, vd: pagination, expand, dropdown selection>
#
# --- Display Logic Matrix (tùy chọn — BẮT BUỘC nếu display logic phụ thuộc ≥2 chiều; Pre-merge yêu cầu) ---
# Liệt kê đủ ma trận N×M case + map mỗi case → SC. Tên SC theo pattern `<cấu trúc>: <outcome>` (KHÔNG dùng "(Case X)").
# | # | Dim1 | Dim2 | Format hiển thị        | SC   |
# |---|------|------|------------------------|------|
# | 1 | 0    | 0    | `Tên hàng`             | SC{} |
# | 2 | 0    | 1    | `Tên hàng (đơn vị)`    | SC{} |
# | ... | ...  | ...  | ...                    | ...  |

Feature: <Feature name>
  As a <role>
  I want to <action>
  So that <business value>

  Background:
    Given <precondition dùng chung — dùng alias từ dataset, không phải ID kỹ thuật>

  # ==========================================================
  # NHÓM 1: <Business theme> (<BR refs>)
  # ==========================================================

  # Side-effects: <liệt kê ngắn các Then side-effect cần verify>
  # @trace.scenario: {TICKET-ID}-UC{N}-SC1
  # @trace.sc_version: 1.0
  # @trace.business_rules: {TICKET-ID}-UC{N}-BR1
  @happy
  Scenario: <mô tả business outcome — dùng động từ chính xác: create/receive/assign/block>
    Given <input state — alias từ dataset>
    When <single action>
    Then <main observable outcome>
      And <side-effect 1 khai báo trong header>

  # Side-effects: <...>
  # @trace.scenario: {TICKET-ID}-UC{N}-SC2
  # @trace.sc_version: 1.0
  # @trace.business_rules: {TICKET-ID}-UC{N}-BR1
  @happy @alternative
  Scenario: <cùng theme NHÓM 1 nhưng path khác — vd: giá trị enum khác>
    Given <state>
    When <action>
    Then <outcome>

  # ==========================================================
  # NHÓM 2: <Business theme 2> (<BR refs>)
  # ==========================================================

  # Side-effects: <...>
  # @trace.scenario: {TICKET-ID}-UC{N}-SC3
  # @trace.sc_version: 1.0
  # @trace.business_rules: {TICKET-ID}-UC{N}-BR2
  @edge
  Scenario: <scenario boundary / error>
    Given <state>
    When <action>
    Then <expected error handling>

# === PRD COVERAGE (C.1 + C.2) ===
# AC mapping:
#   AC1 (...) → SC1, SC2
#   AC2 (...) → SC3
# BR mapping (mỗi bullet PHẢI có ≥1 SC — C.2):
#   {TICKET-ID}-UC{N}-BR1 (...) → SC1, SC2
#   {TICKET-ID}-UC{N}-BR2 (...) → SC3
# Wireframe mapping (mỗi component/action ≥1 SC — C.1):
#   Screen "<screen name>":
#     [x] <action 1>  → SC1
#     [x] <action 2>  → SC2
#     [ ] <action 3>  → MISSING ← BLOCK MERGE
# Design Spec coverage (chỉ FE/App — C.1 mở rộng; bỏ khối này nếu không nạp design-spec):
#   Screen "<screen>": loading → SC?, error → SC?, empty → SC?
#   AC-UI behavioral: AC-UI3 (lỗi+khôi phục) → SC?, AC-UI4 (empty CTA) → SC?
#     (bỏ AC-UI visual thuần: AC-UI1 khớp Figma, AC-UI5 WCAG — Designer/QA review riêng)

# === PRE-MERGE CHECKLIST ===
# - [ ] Mỗi SC có Side-effects + @trace.scenario + @trace.sc_version + @trace.business_rules
# - [ ] Coverage Matrix: 0 dòng MISSING (C.1)
# - [ ] FE/App: mỗi Screen State (≠default) + AC-UI behavioral của design-spec có ≥1 SC (C.1 mở rộng)
# - [ ] Mỗi AC/BR map tới ≥1 SC (C.2)
# - [ ] 0 banned term (C.4) — grep file trước khi merge
# - [ ] Feature ≥3 SC có NHÓM grouping theo business theme (C.5)
# - [ ] Nếu popup/modal: khai báo Popup/Modal Lifecycle trong BUSINESS DEFINITION
# - [ ] Nếu display logic ≥2 chiều: Display Logic Matrix trong BUSINESS DEFINITION

```

*(Template `.feature` là **single-source** ở `templates/feature.template` — sửa file đó để đổi cấu trúc mọi `.feature` sinh ra. Coverage Matrix + Pre-merge Checklist nằm ở **cuối** template, thêm vào cuối mỗi file.)*

---

## Write Trace State

Sau khi sinh tất cả file `.feature`, tạo hoặc cập nhật **sổ trace theo platform** `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv` cho mỗi UC — một sổ riêng cho `system` / `web` / `app`. Vì `sc_id` = `{UC-ID}-SC{N}` chỉ độc nhất trong (UC × platform) (mỗi platform tự đánh số SC từ 1), **mỗi platform một file** để scenario platform này không đè/xoá platform khác. Lệnh luôn biết `active_platform` (từ Platform Selection / Service Detection) nên chỉ ghi đúng sổ của platform đang gen.

> **Umbrella + `spec_source`:** cả file `.feature` **và** trace `.tsv` đều ghi vào **spec repo** (`{spec_source}/specs/{domain}/{prd-slug}/bdd/…` và `{spec_source}/.trace/{domain}/{prd-slug}/…`, do context-loader phân giải) — một thao tác ghi **single-repo**, commit/push vào spec submodule. (Trace được gộp trong spec repo để PM quản lý mọi status ở một chỗ; các lệnh phía code cập nhật liên-repo sau.)

**Cột TSV (tab-separated, một header row + một data row cho mỗi scenario):**
```
sc_id\tsc_title\tspec_ver\tgen_ver\timplemented_by\ttest_count\ttest_classes\tdev_selftest\tdev_selftest_at\tqc_status\tqc_run_at\tqc_owner\tqc_blocked_by\tprd_version\tbdd_version\ttech_doc_revision\tfe_tech_doc_revision\tprd_status\tuc_status\tfe_phase\tstatus\tlast_updated
```

**Rules:**
- Nếu file chưa tồn tại → tạo với header row + tất cả scenario row.
- Nếu file tồn tại (gen lại) → với mỗi SC trong `.feature` mới:
  - SC đã có trong `.tsv` VÀ `spec_ver` không đổi → chỉ cập nhật: `sc_title`, `prd_version`, `bdd_version`, `prd_status`, `uc_status`, `last_updated`. Giữ nguyên các cột khác.
  - SC đã có trong `.tsv` VÀ `spec_ver` đổi (scenario bị sửa) → cập nhật: `sc_title`, `spec_ver`, `prd_version`, `bdd_version`, `prd_status`, `uc_status`, `last_updated` VÀ set `status = DRIFT` ngay (để TSV phản ánh drift mà không cần đợi `/validate-traces`). Giữ nguyên `gen_ver`, `implemented_by`, `test_count`, `test_classes`, `tech_doc_revision`, `fe_tech_doc_revision`.
  - SC mới (thêm trong lần gen lại này) → append row mới với `gen_ver`, `implemented_by`, `test_count`, `test_classes`, `dev_selftest`, `dev_selftest_at`, `qc_status`, `qc_run_at`, `qc_owner`, `qc_blocked_by`, `tech_doc_revision`, `fe_tech_doc_revision` đều set `—`.
  - SC không còn trong `.feature` (bị xoá) → xoá row của nó. *(An toàn: sổ này chỉ chứa scenario của `{active_platform}`, so với `.feature` của chính platform đó — không bao giờ đụng scenario platform khác.)*

**Giá trị ghi cho mỗi scenario:**

| Cột | Giá trị |
|--------|-------|
| `sc_id` | `{UC-ID}-SC{N}` |
| `sc_title` | text title của scenario |
| `spec_ver` | `@trace.sc_version` của scenario này |
| `gen_ver` | `—` (chưa gen) |
| `implemented_by` | `—` |
| `test_count` | `—` |
| `test_classes` | `—` |
| `dev_selftest` | `—` (chưa chạy test) |
| `dev_selftest_at` | `—` |
| `qc_status` | `—` (kết quả QC automation chính thức — set bởi `/qc-run-test`) |
| `qc_run_at` | `—` |
| `qc_owner` | `—` (SC chưa pass đang chờ ai: `dev` / `po` — set bởi `/qc-run-test` + `/report-bug`) |
| `qc_blocked_by` | `—` (`BUG-{id}` / `GAP-{id}` liên kết — set bởi `/qc-run-test` + `/report-bug`) |
| `prd_version` | `@trace.prd_version` từ header `.feature` |
| `bdd_version` | `@trace.bdd_version` từ header `.feature` |
| `tech_doc_revision` | `—` (revision tech-doc gộp `{TICKET-ID}-tech-design.md` — set bởi `/generate-code` + `/review-tech-docs`) |
| `fe_tech_doc_revision` | `—` (revision cùng tech-doc gộp, ghi khi FE `--phase=integration` wire theo §4.5.4 — set bởi `/generate-code`) |
| `prd_status` | đọc `\| **Status** \|` từ metadata PRD |
| `uc_status` | `draft` cho UC mới; giữ giá trị hiện có khi gen lại |
| `fe_phase` | `—` (set bởi `/generate-code --phase` khi FE implement) |
| `status` | `UNTRACKED` |
| `last_updated` | hôm nay `YYYY-MM-DD` |

## Refresh Panel Mirror
# Làm mới panel mirror của Living Docs *(local, chế độ umbrella)*

*Bỏ qua hoàn toàn ở chế độ single-service (không có `services` và không có `setup.spec_source`) — ở đó
`.trace/` của chính repo CHÍNH LÀ vị trí panel, nên không có gì để mirror.*

Sau khi cập nhật TSV authoritative tại `{paths.trace_dir}`:

**Khi `setup.spec_source` được đặt (trace gộp — trường hợp phổ biến):**
`{paths.trace_dir}` phân giải về `{spec_source}/.trace` — vị trí authoritative duy nhất.
Lệnh này chạy từ `service_root`, nên thao tác ghi là **liên-repo vào spec submodule**;
commit/push spec submodule cho lần cập nhật trace (giống như `feedback/`).
1. Phân giải `panel_mirror = ./.trace` tại **gốc workspace hiện tại**.
2. Nếu `panel_mirror` phân giải ra path khác với `{paths.trace_dir}`, copy mỗi
   `{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{UC-ID}-{platform}.tsv` (tạo thư mục; ghi đè).
   Không namespace theo service — chỉ có một bộ trace; service sở hữu được mang trong
   `@trace.service` của từng row.

**Legacy (không có `spec_source` — trace theo service):**
Copy mỗi `{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{service-name}/{UC-ID}-{platform}.tsv`
(namespace theo `active_service`).

Cách này giữ panel Living Docs của workspace đang mở luôn mới **giữa các lần sync** — nó chỉ là
một **mirror tiện lợi cục bộ**. File `trace-report.json` đã merge (canonical, trong
`{spec_source}/.living-docs/`) được build lại bởi `/sync` hoặc `/validate-traces`. Với các lệnh
được orchestrate, làm việc này một lần trong orchestrator sau khi tất cả sub-agent trả về — không phải
bên trong từng sub-agent.


## Output

# Report Footer — Định dạng output chuẩn cho mọi lệnh

Mọi report của lệnh phải kết thúc bằng section footer chuẩn này.

## Status Badge

Chọn một theo kết quả:
- `✅ Complete` — mọi bước thành công, không có vấn đề
- `❌ Failed` — lệnh không hoàn thành được do lỗi chặn
- `⚠️ Warnings` — hoàn thành nhưng có vấn đề không chặn, nên review lại

## Output Artifacts

Liệt kê mọi file được tạo hoặc sửa bởi lệnh này:
```
Output Artifacts:
  {created|updated} {file-path} ({mô tả ngắn})
  {created|updated} {file-path} ({mô tả ngắn})
```

Nếu không ghi file nào (vd: lệnh review hoặc phân tích) → ghi `Output Artifacts: none (read-only)`.

## Pipeline Position

In một sơ đồ pipeline một dòng, đánh dấu phase của lệnh HIỆN TẠI bằng `◀ bạn ở đây`,
để người dùng luôn thấy lệnh này nằm ở đâu trong luồng end-to-end:

```
Discovery → PRD → [Design Spec] → BDD → Tech Design → Code → Dev Self-Check → QC → Trace Audit
```

Tìm lệnh hiện tại trong bảng phase dưới đây và đánh dấu **phase của nó** trong sơ đồ trên:

| Phase | Commands |
|-------|----------|
| Discovery | `/define-product` |
| PRD | `/generate-prd` · `/refine-prd` · `/review-context` (PRD) |
| Design Spec | `/generate-design-spec` |
| BDD | `/generate-bdd` · `/review-context` (BDD) |
| Tech Design | `/generate-tech-docs` · `/map-testids` · `/review-tech-docs` |
| Code | `/generate-code` · `/review-code` |
| Dev Self-Check | `/dev-gen-test` · `/dev-run-test` · `/dev-smoke-test` |
| QC | `/qc-analyze` · `/qc-plan` · `/qc-design-test` · `/qc-review` · `/qc-run-test` · `/qc-report` |
| Trace Audit | `/validate-traces` |

Với **lệnh review**, thêm vòng review 3 bước và đánh dấu bước hiện tại, vd:
`Vòng review: [① phân tích ◀] → ② Review Board → ③ --resume`.

**Lệnh xuyên suốt** (`/sync`, `/update-framework`, `/fix-bug`, `/debug`, `/learn`,
`/report-bug`, `/propose-scenario`, `/generate-spec-manifest`) nằm ngoài pipeline tuyến tính —
**bỏ hẳn dòng Pipeline** cho các lệnh này (đừng cố nhét chúng vào sơ đồ).

## Gợi ý lệnh tiếp theo

Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:

| Lệnh hiện tại           | Gợi ý lệnh tiếp theo                          |
|-------------------------|-----------------------------------------------|
| /setup-ai-first         | `/define-product` để bắt đầu feature đầu tiên |
| /define-product         | `/generate-prd {product-definition-file}`     |
| /generate-prd           | `/refine-prd {prd-file}` rồi `/review-context {prd-file}` |
| /refine-prd             | Mở Review Board → cập nhật PRD → `/review-context {prd-file}` |
| /review-context (PRD)   | Khi 0 critical → PO đặt `Status: approved`, rồi FE/App: `/generate-design-spec {prd-file}` (→ design sign-off → BDD); BE: `/generate-bdd {prd-file}`. Còn critical/NEEDS_FIX → sửa PRD (giữ draft) |
| /generate-design-spec   | Designer review → xác nhận link Figma → PO + Designer sign-off → `/generate-bdd {prd-file}` |
| /generate-bdd           | `/review-context {feature-file}` để kiểm tra độ phủ |
| /review-context (BDD)   | `/generate-tech-docs {UC-ID}` nếu APPROVED; sinh lại nếu NEEDS_FIX |
| /qc-analyze             | `/qc-plan {UC-ID}` (xử lý các gap blocker 🔴 trước) |
| /qc-plan                | `/qc-design-test {UC-ID}`                     |
| /qc-design-test         | `/qc-review {UC-ID}` (review test-case)       |
| /qc-review (test-case)  | `/qc-run-test {UC-ID}` nếu APPROVED; sửa TC nếu NEEDS_FIX |
| /qc-run-test            | `/qc-report {UC-ID}` rồi `/qc-review {UC-ID}` (review script) |
| /qc-review (script)     | `/qc-report {UC-ID}` rồi tạo PR nếu APPROVED |
| /qc-report              | `/validate-traces {UC-ID}` để làm mới Living Docs (qc_status) |
| /generate-tech-docs     | `/review-tech-docs {tech-design-file}`        |
| /review-tech-docs       | `/generate-code {feature-file}` nếu APPROVED; sửa doc nếu NEEDS_FIX |
| /generate-code          | Lần gen đầu → `/review-code {UC-ID}`; gen lại → `/dev-gen-test {UC-ID}` |
| /dev-gen-test         | `/dev-run-test {UC-ID}`                          |
| /dev-run-test (passing)    | `/review-code {UC-ID}`                        |
| /dev-run-test (failing)    | `/fix-bug {ticket-id}` hoặc `/debug {error}`    |
| /review-code            | `/dev-smoke-test {UC-ID}` hoặc tạo PR            |
| /dev-smoke-test             | Tạo PR và link tới ticket                  |
| /validate-traces        | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/dev-gen-test {UC-ID}`; tất cả OK → tạo PR |
| /fix-bug                | Tạo PR và link tới ticket                  |
| /debug                  | `/fix-bug {ticket-id}` nếu cần sửa          |
| /report-bug             | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
| /propose-scenario       | Báo PO/Dev review proposal trong `feedback/bdd-proposals/` |
| /learn                  | Tiếp tục làm việc — lesson áp dụng ở lệnh kế tiếp |
| /sync                   | `/validate-traces` để xem độ phủ đầy đủ; xử lý mọi `📥 tester feedback` được nêu |
| /update-framework       | Review `git diff .agent/`, commit; `/sync` để đồng bộ nội dung dự án |

Định dạng footer như sau:
```
---
Status   : {badge}
{khối Output Artifacts}
Pipeline : Discovery → PRD → [BDD ◀ bạn ở đây] → Tech Design → Code → Dev Self-Check → QC → Trace Audit
           (lệnh review) Vòng review: [① phân tích ◀] → ② Review Board → ③ --resume
Next     : {lệnh gợi ý kèm ví dụ tham số}
```
*(Bỏ dòng `Pipeline` cho các lệnh xuyên suốt liệt kê ở trên.)*


```
/generate-bdd Hoàn tất

[Spec repo mode — platform: {active_platform}]
Files:
  {paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC1-{slug}.feature ({N} scenarios)
  {paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC2-{slug}.feature ({N} scenarios)
Trace:
  {paths.trace_dir}/{domain}/{prd-slug}/{TICKET-ID}-UC1-{active_platform}.tsv ({N} rows)
  {paths.trace_dir}/{domain}/{prd-slug}/{TICKET-ID}-UC2-{active_platform}.tsv ({N} rows)
Next (spec repo):
  → Chạy /generate-bdd lại cho các platform khác (web → app → system)
  → Sau khi gen hết platform: commit + push + báo team dev
  → Team dev đọc BDD từ spec submodule — không chạy /generate-bdd ở phía họ

[Umbrella mode — service: {active_service}]
Files:
  {paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC1-{slug}.feature ({N} scenarios)
Trace:
  {paths.trace_dir}/{domain}/{prd-slug}/{TICKET-ID}-UC1-{active_platform}.tsv ({N} rows)
Next (umbrella):
  → /review-context {feature-file} để kiểm tra coverage
  → /generate-tech-docs {feature-file}
  → /generate-code {feature-file}

📊 Living Docs: chạy /validate-traces (hoặc /sync) để push trace này lên dashboard spec-module.
```
