# /review-tech-docs — Review Technical Design Document

**Chế độ phân tích READ-ONLY — ghi file findings, KHÔNG sửa target.**
**Dùng `--resume` để áp dụng các finding được chấp nhận.**

## 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ì.


*Lưu ý: Với lệnh này, target ở Bước 1 là **file tech-design gộp của PRD** `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` — MỘT doc full-stack phủ mọi UC của PRD (không còn per-UC / per-platform). Review chạy trên cả doc; findings gom theo từng UC (đọc §10 UC Coverage để biết finding thuộc UC nào).
Nếu `$ARGUMENTS` chứa `--resume` → bỏ qua sang Resume Mode bên dưới.*

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


---

## Nạp tài liệu Review

Sau khi nạp context nền, đọc các thứ sau theo thứ tự:

1. **Tech-doc target** — đọc đầy đủ. Trích từ header:
   - `@trace.ucs` → danh sách UC mà doc phủ (đối chiếu §10 UC Coverage)
   - `@trace.domain` → domain
   - `@trace.prd` → TICKET-ID của PRD nguồn
   - `@trace.platforms` → các platform có mặt (system / web / app)
   - `@trace.status` → status hiện tại (draft / in-review / approved)

2. **Các file BDD nguồn** — nạp **mọi** feature của PRD này: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/**/*.feature` (system/web/app). Đây là nguồn đối chiếu cho T3/T7 — mỗi UC trong doc phải trace về scenario BDD tương ứng.

3. **Index endpoint cho T4 (KHÔNG nạp full doc khác)** — trích danh sách endpoint (§4.1) + entity chính của doc target. T4 sẽ `grep` các path đó trong `{paths.tech_docs_dir}/{domain}/*/tech-docs/*-tech-design.md` (các PRD khác) và chỉ nạp đoạn liên quan **khi có va chạm** — xem T4.

4. **Tham chiếu kiến trúc** — xác nhận lại CLAUDE.md §2: thứ tự layer, quy tắc kiến trúc.

5. **Core entities** — đã nạp trong context (Bước 6 của context-loader).

6. **PRD nguồn — §Business Rules (cho T8)** — nạp file PRD `{paths.specs_dir}/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md`, trích bảng Business Rule/Business Logic của các UC mà doc phủ. Đây là nguồn đối chiếu-ngược của **T8** (BR nào yêu cầu nguồn/sự kiện/generic-contract mà doc bỏ sót). Chỉ đọc §BR + §AC liên quan — KHÔNG cần toàn PRD.

Suy ra tên file findings (per-PRD):
`{paths.refinement_dir}/{TICKET-ID}-tech-review-findings.yaml`

---

## Review Dimensions

### T1 — Architecture Alignment *(luôn CRITICAL nếu vi phạm)*

Đối chiếu design đề xuất với quy tắc CLAUDE.md §2:

| Loại vi phạm | Severity |
|----------------|----------|
| Controller gọi Repository trực tiếp (skip layer) | Critical |
| Business logic trong Controller hoặc DTO | Critical |
| Pattern bị cấm từ §3 | Critical |
| Phụ thuộc đi ngược upstream (Service → Controller DTO) | Critical |
| Annotation transaction sai layer | Major |
| Thiếu tách lớp (không có Facade khi kiến trúc yêu cầu) | Major |

Với mỗi finding:
```
Component: {tên class hoặc method}
Violates:  "{rule text}" (CLAUDE.md §2)
Fix:       {layer/component nào nên sở hữu cái này}
```
→ **Không auto-fix.** Người phải quyết định fix cấu trúc. Bắt buộc note trong Review Board.

### T2 — Entity Consistency

Dùng catalog core-entities đã nạp:

| Vấn đề | Severity | Auto-fixable? |
|-------|----------|---------------|
| Entity được nhắc nhưng không có trong core-entities.md | Major | No — người confirm là DTO hay domain entity |
| Tên field khác core-entities.md | Major | Yes — đổi về canonical |
| Quan hệ được mô tả khác đi | Major | No — người quyết định |
| Entity mới được đưa ra nhưng chưa có trong core-entities.md | Minor | No — thêm vào core-entities trước |

### T3 — BDD Traceability

Đối chiếu với **mọi** feature BDD của PRD (system/web/app). Với mỗi UC trong §10 UC Coverage, kiểm tra design khớp scenario **2 chiều**.

> ⚠ **SC scope theo platform:** `{UC}-SC{N}` chỉ unique trong (UC × platform) — `system UC1-SC1` và `web UC1-SC1` là **hai scenario khác nhau**. Khi đối chiếu, match SC **trong đúng lane platform** (system SC ↔ system BDD, web SC ↔ web BDD, app SC ↔ app BDD). KHÔNG so chéo platform. §5 phải để mỗi SC trong lane 5.A/5.B/5.C của nó; §10 mỗi dòng có cột Platform.

| Vấn đề | Severity | Auto-fixable? |
|-------|----------|---------------|
| Tech-doc đề xuất behavior không có trong scenario BDD nào (cùng platform) | Major | No — tạo scenario trước |
| Tech-doc mâu thuẫn một scenario BDD | Critical | No — giải quyết conflict trước |
| Scenario (platform, SC) không có design tương ứng (thiếu ở §5 lane hoặc §10) | Minor | Yes — thêm design note còn thiếu |
| §10 UC Coverage sót một (platform, SC) đã có BDD | Major | Yes — thêm dòng coverage + section tương ứng |
| SC ghi trong §5/§10 **không kèm platform** (bare `UC1-SC1`) → nhập nhằng | Major | Yes — gắn platform vào SC ref |

### T4 — Cross-PRD Endpoint Conflict Check *(targeted, load-on-hit)*

Mỗi PRD giờ chỉ 1 doc → xung đột TRONG doc đã do **T5** lo. T4 chỉ soi xung đột **liên-PRD** theo cách rẻ, KHÔNG nạp full doc khác:

1. Trích danh sách endpoint (method + path, §4.1) + entity chính của doc target.
2. `grep` từng path/entity đó trong `{paths.tech_docs_dir}/{domain}/*/tech-docs/*-tech-design.md` (trừ target) — chỉ đọc dòng match.
3. **Chỉ khi có va chạm** (một path/entity xuất hiện ở doc PRD khác) → nạp đúng đoạn §4.1/§4.2 (hoặc §3) của doc đó để so shape.

| Vấn đề *(chỉ khi grep dính)* | Severity | Auto-fixable? |
|-------|----------|---------------|
| Cùng endpoint path, request/response khác shape giữa 2 PRD | Critical | No — người giải quyết |
| Cùng service method với behavior khác | Critical | No — người giải quyết |
| Status transition của cùng entity khác nhau giữa các doc PRD | Critical | No — người giải quyết |
| Trách nhiệm chồng lấn (2 PRD cùng nhận sở hữu 1 endpoint/logic) | Major | No — người giải quyết |

Không có va chạm grep → T4 pass, không nạp thêm gì.

### T5 — Internal Consistency

Trong nội bộ tech-doc:

| Check | Severity | Auto-fixable? |
|-------|----------|---------------|
| Sequence diagram thể hiện flow khác phần mô tả viết | Major | No |
| API spec return type khác code sketch | Major | Yes — căn chỉnh cái này theo cái kia |
| Section tham chiếu một component/concept không bao giờ được định nghĩa sau đó | Minor | Yes — thêm định nghĩa |
| Assumption được nêu nhưng không design nào xử lý nó | Minor | Yes — thêm note hoặc bỏ assumption |

### T6 — Structural Completeness

Kiểm tra tất cả section chuẩn có mặt và không rỗng:

| Section | Missing severity |
|---------|-----------------|
| Header (`@trace.prd`, `@trace.ucs`, `@trace.domain`, `@trace.status`) | Major |
| Overview / Context | Major |
| Architecture Decision kèm lý do | Major |
| Component Diagram hoặc Layer Description | Major |
| Sequence Diagram hoặc Flow Steps | Major |
| API Contract (nếu hướng HTTP) | Major |
| Data Model Changes (nếu entity đổi) | Major |
| Error Handling Strategy | Major |
| Open Questions / Assumptions | Minor |

→ Mọi finding section-thiếu T6 đều **auto-fixable**: AI thêm skeleton section kèm prompt.

### T7 — Cross-Team API Contract Review

*Chỉ áp dụng khi TẤT CẢ điều sau đúng:*
*1. Doc có phần backend/API (`@trace.platforms` gồm `system`, tức PRD có System BDD).*
*2. Header tech-doc KHÔNG có `@trace.api_source: existing`.*

*Nếu `@trace.api_source: existing` → **skip T7 hoàn toàn**. Contract đã được PO xác định trong PRD — không có API design mới để đồng thuận.*

Dimension này đảm bảo team FE, App, và BE đều đồng thuận API contract trước khi bắt đầu implement.

**Step 1 — Check status sign-off trong header tech-doc:**

Đọc block `@trace.sign_off` trong header tech doc. Nếu vắng → thêm như một finding (auto-fixable: thêm skeleton).

```yaml
# @trace.sign_off:
#   be_team:  pending    # author — set "done" khi BE hài lòng với design
#   fe_team:  pending    # FE/Web — phải confirm contract khớp expectation của web BDD
#   app_team: pending    # App — phải confirm contract khớp expectation của app BDD (nếu áp dụng)
#   sa:       pending    # SA/Tech Lead — approval cuối
```

**Step 2 — Contract vs BDD cross-check:**

Nạp web và app BDD cho TICKET-ID này (từ `{paths.specs_dir}/{domain}/{prd-slug}/bdd/web/` và `{paths.specs_dir}/{domain}/{prd-slug}/bdd/app/` trong spec submodule hoặc spec repo).

Với mỗi platform BDD, kiểm tra API contract của tech doc có thoả các mệnh đề `Then` của BDD không:

| Check | Severity |
|---|---|
| Field response trong API contract không phủ những gì web BDD `Then` mong | Critical |
| Field response trong API contract không phủ những gì app BDD `Then` mong | Critical |
| Shape error response không khớp những gì các platform BDD mong | Major |
| Annotation `@system.resolution` của System BDD mâu thuẫn với design API contract | Critical |

**Step 3 — Report sign-off pending:**

Sau review, liệt kê các sign-off còn `pending`:

```
⏳ Sign-off pending trước khi tech docs được approve:
  fe_team  — team FE/Web phải confirm API contract khớp expectation web BDD
  app_team — team App phải confirm API contract khớp expectation app BDD
  sa       — SA/Tech Lead approval cuối

Khi thu đủ sign-off → cập nhật @trace.sign_off trong header tech doc, rồi chạy lại /review-tech-docs.
Tech docs không thể set "approved" khi còn bất kỳ sign-off bắt buộc nào pending.
```

**Approval gate:**
- Nếu `be_team: done` VÀ `fe_team: done` VÀ `app_team: done` (hoặc N/A) VÀ `sa: done` → tech docs có thể set `approved`
- Ngược lại → `@trace.status` giữ `in-review` — `generate-code` bị chặn

### T8 — Reconciliation & Completeness

*Bắt lỗi "đóng kín" + "coverage ≠ completeness" — cái mà Self-Review Gate của `generate-tech-docs` (Cổng 1/4) đáng lẽ chặn. Đối chiếu doc với PRD Business Rules, core-entities, và seam UC anh em (đọc-ngược có giới hạn — không kéo toàn bộ BDD của PRD).*

> **Nguyên tắc:** "mọi SC được map" (T3) là *cần*, KHÔNG *đủ*. T8 fail một doc dù T3 pass, nếu nó thiếu/mâu thuẫn ở tầng rộng hơn lát BDD.

> **Thuật ngữ cross-service (đọc nhanh):** *dedup* = cùng event tới ≥2 lần chỉ xử lý 1 lần (idempotency key) · *ordering* = event đúng thứ tự phát ra, hoặc bên nhận chịu được lệch · *ack path* = bên nhận xong báo lại bên gửi để ngừng gửi lại (thiếu → mất event / gửi lại vô hạn) · *cross-field invariant* = ràng buộc luôn đúng giữa nhiều field (vd `paid ⇒ paid_at ≠ null`).

| Vấn đề | Severity | Auto-fixable? |
|---|---|---|
| Enum/trạng thái dùng trong doc nhưng **không có producer** (không luồng nào sinh giá trị đó) | Major | No — người xác định owner |
| Cột/field ghi nhưng **không có writer** (không luồng nào set) | Major | No |
| **PRD Business Rule** yêu cầu một nguồn/sự kiện mà doc **bỏ sót** | Critical | No — thêm design trước |
| PRD-BR đưa **hợp đồng chung** (generic envelope) nhưng doc tự làm **typed-per-thing** | Major | No |
| **Leak boundary** — kéo định danh nội bộ của service khác vào lookup của mình thay vì abstraction tầng mình | Major | No |
| Cross-service **không tách** bên nào own dedup/ordering, hoặc thiếu **ack path** | Major | No |
| **Cross-field invariant** giữa các field/entity không được nêu | Minor | Yes — thêm note |

### T9 — Gap Honesty & Constants

*Bắt "bịa lặng" + "hard-code" + "happy-only" — cái mà Self-Review Gate Cổng 2/3/4 đáng lẽ chặn.*

| Vấn đề | Severity | Auto-fixable? |
|---|---|---|
| Policy/type/giá trị nêu **như fact không nguồn** (bịa), lẽ ra phải là `[GAP]`/`[ASSUMPTION]` | Critical | No — người xác nhận nguồn hoặc giữ GAP |
| Chỗ đáng lẽ khai gap lại **bỏ trắng / chép hình dạng ở boundary** | Major | No |
| **Constant/literal inline** như luật (chưa vào catalog / chưa đặt tên) | Major | Yes — tách vào bảng constants/enum |
| **Happy-only** — API/flow thiếu partial + error case + rollback | Major | No — thiết kế nhánh lỗi trước |
| **Hàm cốt lõi** được đặt tên nhưng **không tả** điều kiện chọn / nhánh / kết quả (dừng ở tên hàm + sequence-diagram) | Major | No — cần người bổ sung impl-spec |
| BDD **mâu thuẫn** invariant kiến trúc mà doc **lặng chép** thay vì ghi conflict + escalate PO sửa `.feature` | Critical | No — escalate, không tự quyết |
| Citation/tham chiếu **không resolve** (trỏ tới thứ không được định nghĩa) / policy nêu như fact | Minor | Yes — thêm định nghĩa hoặc bỏ ref |
| `[GAP]`/`[ASSUMPTION]` inline **mồ côi** — không có dòng ở §12 GAP Register (hoặc dòng §12 không có marker inline) | Major | Yes — đồng bộ register ↔ marker |
| §12 GAP Register còn **🔴 blocker `open`** (chưa đóng) | Critical | No — chặn approve tới khi owner đóng. *(GAP đã khai đúng KHÔNG tính là "bịa" — đây là finding về gate, không phạt trung thực)* |

> **T8/T9 phản chiếu Self-Review Gate** (4 cổng) của `generate-tech-docs` và `project-lessons` **L-012** — nếu gen bỏ lọt, cổng review bắt lại. Đặt trong nguồn `.tmpl` nên bền qua `/update-framework`.

---

## Ghi File Findings

Sau khi chạy hết các check, ghi findings vào `{paths.refinement_dir}/{TICKET-ID}-tech-review-findings.yaml`:

```yaml
source_file: "{absolute path to tech-doc}"
prd_id: "{TICKET-ID}"
ucs: [{UC-ID list phủ bởi doc}]
domain: "{domain}"
generated_at: "{ISO datetime}"
review_type: "tech-design"
status: "pending_review"
is_system_bdd: {true | false}  # true nếu doc có phần backend (@trace.platforms gồm system)

sign_off:                       # chỉ có khi is_system_bdd: true
  be_team:  pending             # đọc từ @trace.sign_off trong header tech-doc
  fe_team:  pending
  app_team: pending             # "n/a" nếu dự án không có platform app
  sa:       pending
sign_off_gate: blocked          # blocked | ready — "ready" chỉ khi tất cả bắt buộc là "done"

findings:
  - id: "F001"
    check_id: "T1"           # T1–T9
    severity: "critical"     # critical | major | minor
    section: "{section heading hoặc tên component nơi tìm thấy lỗi}"
    uc_id: "{UC-ID}"         # UC mà finding này thuộc về (một trong `ucs`; đọc §10 để xác định)
    quote: "{trích đoạn nguyên văn copy CHÍNH XÁC từ tech-doc tại vị trí lỗi, ≤120 ký tự}"
    finding: "{mô tả rõ ràng vi phạm hoặc gap}"
    suggestion: "{bản fix cụ thể — AI áp dụng khi --resume nếu được chấp nhận}"
    auto_fixable: false      # true = AI áp dụng được; false = người phải ghi quyết định trong note
    status: "pending"        # pending | accepted | modified | rejected | deferred

summary:
  total_findings: {N}
  by_severity: { critical: {N}, major: {N}, minor: {N} }
  auto_fixable: {N}
  requires_human_decision: {N}
  recommendation: "APPROVED | NEEDS_REVISION | BLOCKED"
  sign_off_gate: "{blocked — pending: fe_team, app_team, sa | ready}"
```

> **Field định vị (`quote` + `uc_id`) — bắt buộc cho source-jump của Review Board.**
> Với mỗi finding, copy một đoạn `quote` **nguyên văn** thẳng từ tech-doc tại đúng chỗ
> lỗi xảy ra — KHÔNG diễn giải lại; nó được so khớp với tài liệu để định vị dòng.
> Field này cho phép reviewer click một finding trong Review Board và nhảy tới đúng vị trí nguồn.

## Report

# 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.)*


```
/review-tech-docs Hoàn tất — {target file}
PRD: {TICKET-ID} | UCs: {UC list} | Domain: {domain}
Findings: {total} | 🔴 Critical: {N} | 🟡 Major: {N} | 🟢 Minor: {N}
Auto-fixable: {N} | Needs human decision: {N}

GAP Register (§12): {open_blocker} 🔴 blocker open / {total_open} open / {total} tracked
  {🔒 còn blocker open → chặn approve | ✅ 0 blocker open}

Sign-off gate (chỉ system BDD):
  be_team  : {done | pending}
  fe_team  : {done | pending}   ← {name / "needs sign-off" }
  app_team : {done | pending | n/a}
  sa       : {done | pending}
  Gate     : {🔒 BLOCKED — pending: fe_team, sa | ✅ READY}

File findings: {paths.refinement_dir}/{TICKET-ID}-tech-review-findings.yaml
Next: Mở trong Review Board → Accept/Modify/Reject từng finding
      Rồi chạy: /review-tech-docs --resume {tech-design-file}
      Sau khi thu đủ sign-off → cập nhật @trace.sign_off trong tech doc, chạy lại review
```

---

## Resume Mode — Áp dụng các Finding được chấp nhận

*Kích hoạt khi `$ARGUMENTS` chứa `--resume`.*
*Ví dụ: `/review-tech-docs --resume {paths.tech_docs_dir}/payment/{prd-slug}/tech-docs/PAY-123-tech-design.md`*

### Phase 1 — Đọc các finding được chấp nhận

1. Suy ra file findings từ target: `{paths.refinement_dir}/{TICKET-ID}-tech-review-findings.yaml`
2. Đọc file. Gom các finding có `status: "accepted"` hoặc `status: "modified"`.
3. Nếu không có → báo "No accepted findings. File unchanged." và dừng.

### Phase 2 — Áp dụng fix

Áp dụng theo thứ tự: critical → major → minor.

| check_id | Làm gì |
|----------|-----------|
| T1 (Architecture) | Áp dụng fix cấu trúc từ note finding — chuyển logic về đúng layer, cập nhật mô tả component |
| T2 (Tên field) | Đổi field về tên canonical từ core-entities.md xuyên suốt tài liệu |
| T3 (Thiếu design note) | Thêm design decision note cho scenario chưa phủ |
| T5 (Internal inconsistency) | Căn chỉnh các section mâu thuẫn theo quyết định nêu trong note |
| T6 (Thiếu section) | Thêm skeleton section với prompt placeholder cho tech lead điền |
| T8 (cross-field invariant) | Thêm note invariant còn thiếu *(chỉ mục minor auto-fixable; enum mồ côi / PRD-BR bỏ sót / leak boundary cần người)* |
| T9 (constant / citation) | Tách constant inline vào bảng catalog/enum; thêm định nghĩa cho citation không resolve |

**Finding T1, T2, T4 và các mục Critical/Major của T8/T9 có `auto_fixable: false`:** cần một resolution do người viết trong
note "Modify" của Review Board (enum mồ côi, PRD-BR bỏ sót, leak boundary, bịa-lặng, happy-only, BDD↔kiến trúc mâu thuẫn — không tự đoán). Áp dụng đúng những gì note nói. Đừng bịa fix.

### Phase 3 — Cập nhật header + TSV + Report

Sửa file tech-doc trực tiếp:
1. Tìm `@trace.revision:` trong header — tăng giá trị integer lên 1.
2. Tìm `@trace.status:` trong header. Set `approved` **chỉ khi CẢ HAI**:
   - (a) sign_off_gate = `ready` (tất cả sign-off done; hoặc doc không có phần system → không cần sign-off), **VÀ**
   - (b) §12 GAP Register **không còn 🔴 blocker nào ở trạng thái `open`** (đếm ở T9).
   Thiếu (a) hoặc (b) → set `in-review` (chặn `/generate-code`); ghi rõ lý do vào report (sign-off pending / còn N blocker-GAP open).
3. Nếu block `@trace.sign_off` vắng và đây là tech doc system BDD → thêm nó với tất cả giá trị `pending`.

Ghi cả hai thay đổi vào file.

Rồi cập nhật TSV cho **mọi UC mà doc phủ** (`@trace.ucs`) — doc gộp có một `@trace.revision` chung cho cả BE và client:
- Với mỗi UC trong `@trace.ucs`: glob **mọi sổ platform** `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-*.tsv` (system/web/app), và set `tech_doc_revision` thành integer `@trace.revision` mới cho mọi row trong từng sổ đó.
- **KHÔNG** đụng `fe_tech_doc_revision` ở đây — cột đó do `/generate-code --phase=integration` ghi khi FE thực sự wire adapter theo §4.5.4 (drift-detect riêng cho FE integration).
- Set `last_updated` thành ngày hôm nay (`YYYY-MM-DD`) cho các row vừa chạm.

In report sau khi hoàn tất mọi lần ghi file.

```
/review-tech-docs --resume Đã áp dụng — {target file}
PRD: {TICKET-ID} | UCs: {UC list}

Applied  : {N} findings ({critical} critical, {major} major, {minor} minor)
Skipped  : {N} rejected/deferred

Changes:
  - {change 1}
  - {change 2}

Revision : {old} → {new}
Status   : {approved | in-review}

Sign-off : {✅ Tất cả done — status set approved
           | 🔒 Pending: fe_team, sa — status set in-review
              Cập nhật @trace.sign_off trong tech doc khi mỗi team confirm, rồi chạy lại /review-tech-docs}

Chạy lại /review-tech-docs {file} để xác nhận 0 finding critical còn lại.
Next: {/generate-code {feature-file}  ← chỉ khi status = approved
      | Thu các sign-off pending → cập nhật @trace.sign_off → chạy lại /review-tech-docs}
      → nếu tech-doc sống trong spec repo dùng chung: commit + push lên spec submodule để FE/App `/sync` contract đã cập nhật
```
