@edupia-tutor/spec-driven-docs 0.14.5 → 0.14.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -641,7 +641,7 @@ Trước khi sinh, kiểm tra các file `.feature` có sẵn cho PRD này:
641
641
  - So với version PRD hiện tại.
642
642
  - Nếu **giống** → hỏi: "BDD đã sinh từ PRD v{version}. Gen lại? (Y/N)"
643
643
  - Nếu **khác** (PRD đã cập nhật):
644
- 1. Đọc `## Changelog` từ PRD — trích tất cả row mới hơn `@trace.prd_version` của BDD hiện có.
644
+ 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ó.
645
645
  2. Hiện CHECKPOINT:
646
646
  ```
647
647
  ⚠️ Phát hiện PRD version drift
@@ -246,7 +246,7 @@ Trước khi sinh, kiểm tra các file `.feature` có sẵn cho PRD này:
246
246
  - So với version PRD hiện tại.
247
247
  - Nếu **giống** → hỏi: "BDD đã sinh từ PRD v{version}. Gen lại? (Y/N)"
248
248
  - Nếu **khác** (PRD đã cập nhật):
249
- 1. Đọc `## Changelog` từ PRD — trích tất cả row mới hơn `@trace.prd_version` của BDD hiện có.
249
+ 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ó.
250
250
  2. Hiện CHECKPOINT:
251
251
  ```
252
252
  ⚠️ Phát hiện PRD version drift
@@ -901,7 +901,7 @@ Cập nhật `status: "applied"` ở **root level** của file findings (không
901
901
  - `| **Version** | {new_version} |`
902
902
  - `| **Updated** | {today YYYY-MM-DD} |`
903
903
  - `| **Status** | draft |` ← reset về draft, phải được duyệt lại
904
- 5. Thêm một row mới lên đầu `## Changelog` ở cuối PRD:
904
+ 5. Thêm một row mới lên đầu `# Change Log` ở cuối PRD:
905
905
  ```
906
906
  | {new_version} | {today} | {tóm tắt súc tích mọi thay đổi đã áp dụng} |
907
907
  ```
@@ -218,7 +218,7 @@ Cập nhật `status: "applied"` ở **root level** của file findings (không
218
218
  - `| **Version** | {new_version} |`
219
219
  - `| **Updated** | {today YYYY-MM-DD} |`
220
220
  - `| **Status** | draft |` ← reset về draft, phải được duyệt lại
221
- 5. Thêm một row mới lên đầu `## Changelog` ở cuối PRD:
221
+ 5. Thêm một row mới lên đầu `# Change Log` ở cuối PRD:
222
222
  ```
223
223
  | {new_version} | {today} | {tóm tắt súc tích mọi thay đổi đã áp dụng} |
224
224
  ```
@@ -410,6 +410,47 @@ Sau khi hoàn thành tất cả các bước, bạn đã nạp:
410
410
  Tiếp tục sang bước kế tiếp của lệnh đang gọi.
411
411
 
412
412
 
413
+ ---
414
+
415
+ ## Ngôn ngữ nghiệp vụ *(áp khi viết — Fix Mode & Resume Mode)*
416
+ # Business Language Guard — chặn thuật ngữ kỹ thuật rò vào tài liệu nghiệp vụ
417
+
418
+ Tài liệu nghiệp vụ (PRD, product-definition) mô tả **WHAT** — chỉ ngôn ngữ nghiệp vụ. Guard này chạy **mỗi khi viết hoặc sửa** prose (gen mới, áp fix `--resume`, hiệu chỉnh): **quét và xử lý** các thuật ngữ kỹ thuật/UI phổ thông bên dưới **trước khi ghi**.
419
+
420
+ > Guard này là **baseline framework**, chạy **song song** với Banned Terms của `business-dictionary.md` (cơ chế dictionary giữ nguyên; project vẫn bổ sung term đặc thù vào đó). Khi cả hai cùng áp, ưu tiên bản chuẩn của dictionary nếu có.
421
+
422
+ ## Bản đồ xử lý (3 nhóm)
423
+
424
+ **Nhóm 1 — Tương tác/triển khai → DIỄN ĐẠT LẠI sang nghiệp vụ (giữ nguyên nghĩa):**
425
+
426
+ | Kỹ thuật/UI | Cách nói nghiệp vụ |
427
+ |---|---|
428
+ | re-render / render lại / reload / refresh (màn) | "hiển thị lại {tên màn}" |
429
+ | timeout | "quá thời gian chờ" |
430
+ | lỗi mạng / network error | "lỗi kết nối" |
431
+ | UI / giao diện (khi chỉ một màn) | "màn" / "màn hình" |
432
+ | click / tap | "bấm" / "chọn" |
433
+ | popup / modal (nếu chỉ là khái niệm hiển thị) | "hộp thoại" / "thông báo" |
434
+ | disable / enable (nút) | "khoá" / "mở" thao tác |
435
+ | redirect / navigate | "chuyển tới {màn}" |
436
+
437
+ **Nhóm 2 — Visual thuần → CHUYỂN Design Spec (bỏ khỏi PRD, ghi nhận lại):**
438
+ `spinner`, `loading indicator`, `animation`, `fade/slide`, màu sắc, font, layout pixel, micro-interaction → *"Chi tiết visual này thuộc Design Spec — ghi nhận để tạo Design Spec sau."*
439
+
440
+ **Nhóm 3 — Backend/contract thuần → BỎ khỏi PRD (thuộc Tech Docs):**
441
+ `API`, `endpoint`, `token/JWT`, `HTTP status`, tên class/bảng/cột DB, query, payload, header.
442
+ *(Ngoại lệ DUY NHẤT: Appendix "Existing API Contract" khi `API Source: existing` — xem Platform Strategy.)*
443
+
444
+ ## Quy tắc áp dụng
445
+ - Quét toàn bộ text sắp ghi (User Story, AC, BR, Business Logic, Scope, Edge Cases, Assumptions…).
446
+ - Nhóm 1 → thay tại chỗ, giữ nguyên nghĩa nghiệp vụ. **Đồng bộ cách diễn đạt** với chỗ đã có sẵn trong cùng tài liệu (vd nếu "quá thời gian chờ" đã dùng ở một BR → dùng nhất quán ở mọi nơi).
447
+ - Nhóm 2 → gỡ khỏi prose nghiệp vụ + nhắc chuyển Design Spec.
448
+ - Nhóm 3 → gỡ khỏi PRD (trừ ngoại lệ brownfield).
449
+ - Nếu term không có trong bản đồ nhưng rõ ràng là tên kỹ thuật/triển khai → vẫn diễn đạt lại theo tinh thần Nhóm 1, đừng để lọt.
450
+
451
+ **Checklist (dùng ở Quality Checklist của lệnh):** 0 thuật ngữ kỹ thuật/UI (re-render, UI, timeout, spinner, API/endpoint/token…) trong prose nghiệp vụ — đã diễn đạt lại (Nhóm 1) / chuyển Design Spec (Nhóm 2) / bỏ về Tech Docs (Nhóm 3).
452
+
453
+
413
454
  ---
414
455
 
415
456
  ## Phát hiện Review Mode
@@ -589,6 +630,19 @@ Convergence: {convergence_rounds} vòng critic — file findings đã đầy đ
589
630
  - **Check do orchestrator chạy (không fan out):** `P0` (umbrella routing) và `P3` (xung đột cross-PRD) cần config / context của PRD khác — orchestrator tự chạy chúng **trước** fan-out và thêm kết quả vào `ALL_FINDINGS`.
590
631
  - Vòng lặp completeness-critic (Phase 2) đảm bảo file findings đầy đủ trong một lần chạy — chạy lại `/review-context` sẽ lòi ra **0 finding mới**. Map mỗi dimension vào field `check_id` của schema dưới đây.
591
632
 
633
+ **Tham số truyền vào Quy trình Review:**
634
+ - `GRANULARITY = per-uc` — LUÔN fan-out theo từng UC (bỏ ngưỡng cả-file), để **cổng review bắt đủ lỗi ngay lần đầu** (cổng cuối trước khi sinh BDD — sót ở đây thì test sai theo).
635
+ - `CHANGED_SCOPE` — theo full/delta dưới đây.
636
+
637
+ **Chọn full vs delta** *(mặc định: lần đầu FULL, lần sau DELTA)*:
638
+ 1. Tách `--full` khỏi `$ARGUMENTS` nếu có.
639
+ 2. Kiểm tra file findings của target (tên suy ở "Phát hiện Review Mode"):
640
+ - **Không tồn tại** (lần đầu) → **FULL**: KHÔNG truyền `CHANGED_SCOPE`.
641
+ - **Tồn tại** + có `--full` → **FULL**: bỏ qua findings cũ.
642
+ - **Tồn tại** + KHÔNG `--full` → so `source_version` trong findings cũ với version target hiện tại (PRD: Metadata `Version`; BDD: `@trace.bdd_version`):
643
+ - **Bằng nhau** (target chưa đổi từ lần review trước) → DỪNG, báo: `"Target chưa đổi từ v{X} (lần review gần nhất). Không có gì để review lại — dùng --full nếu vẫn muốn quét toàn bộ."`
644
+ - **Khác** → **DELTA**: `CHANGED_SCOPE` = { `uc_id`/`section` của finding đã xử lý (status `accepted`/`modified`/`applied_automatically`) trong findings cũ } ∪ { UC có trong target hiện tại nhưng chưa từng xuất hiện ở findings cũ }.
645
+
592
646
  ---
593
647
 
594
648
  ## PRD Review Mode
@@ -599,33 +653,35 @@ Convergence: {convergence_rounds} vòng critic — file findings đã đầy đ
599
653
 
600
654
  Khi `setup.mode = umbrella`, PRD phải có metadata routing đúng để context-loader Bước 1.5 có thể đưa output sinh ra tới đúng service submodule. Chạy các check này **trước P1–P5**:
601
655
 
602
- **P0.1 — `@trace.domain` mặt**
603
- - Đọc block frontmatter của PRD (các dòng bắt đầu bằng `@trace.` ở đầu file)
604
- - Nếu `@trace.domain` **vắng mặt** finding **critical**:
605
- - `finding`: "`@trace.domain` đang thiếu. Umbrella routing của team dev phụ thuộc field này để đưa BDD và code output tới đúng service submodule."
606
- - `suggestion`: "Thêm `@trace.domain: {domain}` vào frontmatter của PRD. Dùng một trong các domain key được định nghĩa trong section services của `project-context.yaml` của umbrella."
656
+ > **Nguồn đọc:** PRD mang Domain/Status ở **bảng Metadata** (`| **Domain** | … |`, `| **Status** | … |`) **KHÔNG** phải frontmatter `@trace.*` (cái đó dành cho file `.feature`/tech-docs do máy đọc). Routing umbrella dựa trên Domain (bảng) + path, đúng như context-loader Bước 1.5 và `generate-bdd` (đọc `| **Status** |`).
657
+
658
+ **P0.1 Row `Domain` mặt trong Metadata**
659
+ - Đọc bảng Metadata của PRD, lấy row `| **Domain** |`.
660
+ - Nếu **vắng mặt / để trống** finding **critical**:
661
+ - `finding`: "Row `Domain` trong bảng Metadata đang thiếu. Umbrella routing của team dev phụ thuộc Domain (+ path) để đưa BDD và code output tới đúng service submodule."
662
+ - `suggestion`: "Thêm `| **Domain** | {domain} |` vào bảng Metadata. Dùng một trong các domain key được định nghĩa trong section services của `project-context.yaml` của umbrella."
607
663
  - `auto_fixable: false` — PO phải confirm tên domain đúng
608
664
 
609
- **P0.2 — `@trace.domain` khớp một service key**
610
- - Nếu `@trace.domain` có mặt, kiểm tra giá trị của nó có khớp key nào trong section `services` của project-context.yaml không
665
+ **P0.2 — `Domain` khớp một service key**
666
+ - Nếu Domain có mặt, kiểm tra giá trị của nó có khớp key nào trong section `services` của project-context.yaml không.
611
667
  - Nếu **không khớp** → finding **critical**:
612
- - `finding`: "`@trace.domain: {value}` không khớp key nào trong config `services` của umbrella. Routing sẽ fallback về path mặc định và BDD có thể được sinh sai chỗ."
613
- - `suggestion`: "Hoặc cập nhật `@trace.domain` cho khớp một service key có sẵn ({list known keys}), hoặc thêm entry mới vào `services` trong project-context.yaml cho domain `{value}`."
668
+ - `finding`: "Domain `{value}` không khớp key nào trong config `services` của umbrella. Routing sẽ fallback về path mặc định và BDD có thể được sinh sai chỗ."
669
+ - `suggestion`: "Hoặc cập nhật row Domain cho khớp một service key có sẵn ({list known keys}), hoặc thêm entry mới vào `services` trong project-context.yaml cho domain `{value}`."
614
670
  - `auto_fixable: false`
615
671
  - Nếu section `services` chưa được cấu hình (rỗng/placeholder) → finding **major**:
616
672
  - `finding`: "Section `services` của umbrella chưa được cấu hình. Không thể kiểm chứng domain routing."
617
673
  - `suggestion`: "Cập nhật section services trong `.agent/project-context.yaml` với mapping domain-to-submodule trước khi sinh BDD."
618
674
  - `auto_fixable: false`
619
675
 
620
- **P0.3 — Check `@trace.status`**
621
- - Nếu `@trace.status` vắng mặt → **minor**, `auto_fixable: true` (thêm `@trace.status: draft`)
622
- - Nếu `@trace.status: draft` → **major**, `auto_fixable: false`:
676
+ **P0.3 — Check row `Status` trong Metadata**
677
+ - Nếu row `| **Status** |` **vắng mặt** → **minor**, `auto_fixable: true` (thêm `| **Status** | draft |`)
678
+ - Nếu `Status: draft` → **major**, `auto_fixable: false`:
623
679
  - `finding`: "PRD status là `draft`. Team dev không nên sinh BDD từ một PRD chưa được duyệt."
624
- - `suggestion`: "PO/SA nên review và cập nhật status thành `approved` trước khi team dev tiếp tục."
680
+ - `suggestion`: "PO/SA nên review và cập nhật Status thành `approved` trước khi team dev tiếp tục."
625
681
 
626
682
  > **P0 là một gate check:** Nếu P0.1 hoặc P0.2 cho finding critical, hiển thị cảnh báo trước khi tiếp tục:
627
683
  > ```
628
- > ⚠️ ROUTING WARNING: phát hiện vấn đề @trace.domain.
684
+ > ⚠️ ROUTING WARNING: phát hiện vấn đề Domain trong Metadata.
629
685
  > BDD/code sinh từ PRD này có thể rơi vào sai service submodule.
630
686
  > Giải quyết các finding P0 trước khi chạy /generate-bdd.
631
687
  > ```
@@ -645,6 +701,9 @@ Quét toàn bộ PRD tìm vấn đề thuật ngữ:
645
701
  3. **Business term chưa liệt kê** — các term quan trọng vắng trong dictionary:
646
702
  → Severity: **minor**. Đề xuất thêm vào `business-dictionary.md`.
647
703
 
704
+ 4. **Thuật ngữ kỹ thuật/UI lọt vào prose nghiệp vụ** — theo baseline **Business Language Guard** (re-render, UI, timeout, spinner, API/endpoint/token…), không nằm trong dictionary nhưng vẫn là từ kỹ thuật:
705
+ → Severity: **major**, auto-fixable. `suggestion` theo guard: diễn đạt lại (Nhóm 1) / chuyển Design Spec (Nhóm 2) / bỏ về Tech Docs (Nhóm 3).
706
+
648
707
  ### P2 — Ambiguity Check
649
708
 
650
709
  Quét mỗi AC và BR tìm:
@@ -669,13 +728,20 @@ hoặc định nghĩa lại field/status transition của một entity khác đi
669
728
 
670
729
  ### P4 — Structural Completeness
671
730
 
672
- - [ ] Block Metadata: Version, Author, Date, Status
673
- - [ ] Ít nhất 1 UC với heading `#### {TICKET-ID}-UC{N}:`
674
- - [ ] Mỗi UC có: Description, Actors, Preconditions, Acceptance Criteria, Business Rules
675
- - [ ] section `## Changelog`
731
+ Đối chiếu với cấu trúc template PRD (Metadata · §1 Tổng quan · §2 AC · §3 UC · §4 UI/UX · Appendix · Change Log):
732
+
733
+ - [ ] **Metadata** có: Version, Status, Author, Created, Updated, Domain, Ticket (PO nếu có)
734
+ - [ ] **§1c "Phụ thuộc liên service"** có mặt (hoặc ghi rõ "Không có")
735
+ - [ ] **§2 Acceptance Criteria** (global) có mặt; **mỗi AC** kết thúc bằng ref `_(BR: …)_` (≥1 BR)
736
+ - [ ] **≥1 UC** với heading `#### {TICKET-ID}-UC{N}:`
737
+ - [ ] Mỗi UC có: **Actor, Description, Pre-condition, Post-condition, AC liên quan**, bảng Business Rule (AC là §2 global — UC chỉ trỏ qua "AC liên quan", KHÔNG chứa AC đầy đủ)
738
+ - [ ] **Nhất quán 2 chiều**: tập "AC liên quan" của mỗi UC = tập AC §2 có ref BR trỏ về UC đó
739
+ - [ ] **§4 UI/UX**: có User Flow và **Wireframe** (Wireframe lái coverage BDD C.1)
740
+ - [ ] **API Source nhất quán**: nếu Metadata `API Source: existing` → Appendix "Existing API Contract" đủ method/path/request/response (hoặc có block ⛔ PENDING + con trỏ nguồn); nếu greenfield/partner (API Source trống) → section "Existing API Contract" đã bị **xoá hẳn** (không để bảng rỗng)
741
+ - [ ] Có section `# Change Log`
676
742
  - [ ] Không còn giá trị `{{PLACEHOLDER}}` chưa điền
677
743
 
678
- → Section thiếu: **major**. AI có thể thêm skeleton khi `--resume` nếu được chấp nhận.
744
+ → Section/field thiếu hoặc lệch cấu trúc: **major**. AI có thể thêm skeleton khi `--resume` nếu được chấp nhận. Riêng **"Nhất quán 2 chiều"** lệch → **major**, `auto_fixable: false` (người xác nhận AC↔UC, AI không tự đoán). **API Source: existing thiếu contract** → **major**, `auto_fixable: false` (cần nguồn contract); **greenfield còn sót section "Existing API Contract" rỗng** → **minor**, `auto_fixable: true` (xoá section).
679
745
 
680
746
  ### P5 — Custom Criteria (tuỳ chọn)
681
747
 
@@ -759,6 +825,7 @@ Sau khi chạy hết các check, ghi `{paths.refinement_dir}/{slug}-review-*-fin
759
825
 
760
826
  ```yaml
761
827
  source_file: "{absolute path to reviewed file}"
828
+ source_version: "{version target lúc sinh findings — PRD: Metadata Version; BDD: @trace.bdd_version — dùng chọn full/delta lần chạy sau}"
762
829
  generated_at: "{ISO datetime}"
763
830
  review_type: "{prd | bdd}"
764
831
  status: "pending_review"
@@ -945,9 +1012,12 @@ Với mỗi finding có `auto_fixable: true`, theo thứ tự (critical → majo
945
1012
 
946
1013
  | check_id | Áp dụng gì |
947
1014
  |----------|--------------|
948
- | P0.3 (Thiếu status) | Thêm `@trace.status: draft` vào frontmatter |
1015
+ | P0.3 (Thiếu status) | Thêm row `| **Status** | draft |` vào bảng Metadata |
949
1016
  | P1 (Banned term) | Thay mọi lần xuất hiện banned term bằng canonical term |
950
- | P4 (Structure) | Thêm skeleton section/metadata còn thiếu |
1017
+ | P1 (Thuật ngữ kỹ thuật/UI) | Diễn đạt lại theo Business Language Guard (Nhóm 1) / chuyển Design Spec (2) / bỏ về Tech Docs (3) |
1018
+ | P4 (Structure) | Thêm skeleton section/metadata còn thiếu; greenfield → xoá section "Existing API Contract" rỗng |
1019
+
1020
+ > **Chạy Business Language Guard trên text vừa sửa TRƯỚC khi ghi** (xem section "Ngôn ngữ nghiệp vụ") — không để bản auto-fix tự kéo thuật ngữ kỹ thuật vào.
951
1021
 
952
1022
  **Với file BDD:**
953
1023
 
@@ -1019,11 +1089,13 @@ Mở file findings trong Review Board → rồi chạy: /review-context --resume
1019
1089
 
1020
1090
  Áp dụng theo thứ tự: critical → major → minor.
1021
1091
 
1092
+ > **Chạy Business Language Guard trên text vừa sửa TRƯỚC khi ghi** (xem section "Ngôn ngữ nghiệp vụ") — đặc biệt với P2 (sửa câu mơ hồ) / P4 skeleton: không để bản fix tự kéo thuật ngữ kỹ thuật-UI vào PRD.
1093
+
1022
1094
  **Với finding PRD:**
1023
1095
  | check_id | Làm gì |
1024
1096
  |----------|-----------|
1025
- | P0.3 (Thiếu status) | Thêm `@trace.status: draft` vào frontmatter |
1026
- | P1 (Banned term) | Thay mọi lần xuất hiện banned term bằng canonical term |
1097
+ | P0.3 (Thiếu status) | Thêm row `| **Status** | draft |` vào bảng Metadata |
1098
+ | P1 (Banned term) | Thay banned term bằng canonical; thuật ngữ kỹ thuật/UI → diễn đạt lại theo Business Language Guard |
1027
1099
  | P2 (Ambiguity) | Áp dụng fix nêu trong `suggestion` hoặc note `modified` |
1028
1100
  | P3 (Conflict) | Áp dụng cách giải quyết nêu trong note modified |
1029
1101
  | P4 (Structure) | Thêm section/metadata field còn thiếu |
@@ -17,6 +17,11 @@ Nếu `$ARGUMENTS` chứa `--fix` → bỏ qua sang Fix Mode bên dưới (áp d
17
17
 
18
18
  ---
19
19
 
20
+ ## Ngôn ngữ nghiệp vụ *(áp khi viết — Fix Mode & Resume Mode)*
21
+ {{include:steps/business-language.md}}
22
+
23
+ ---
24
+
20
25
  ## Phát hiện Review Mode
21
26
 
22
27
  Sau khi phân giải target file:
@@ -42,6 +47,19 @@ Suy ra tên file findings output:
42
47
  - **Check do orchestrator chạy (không fan out):** `P0` (umbrella routing) và `P3` (xung đột cross-PRD) cần config / context của PRD khác — orchestrator tự chạy chúng **trước** fan-out và thêm kết quả vào `ALL_FINDINGS`.
43
48
  - Vòng lặp completeness-critic (Phase 2) đảm bảo file findings đầy đủ trong một lần chạy — chạy lại `/review-context` sẽ lòi ra **0 finding mới**. Map mỗi dimension vào field `check_id` của schema dưới đây.
44
49
 
50
+ **Tham số truyền vào Quy trình Review:**
51
+ - `GRANULARITY = per-uc` — LUÔN fan-out theo từng UC (bỏ ngưỡng cả-file), để **cổng review bắt đủ lỗi ngay lần đầu** (cổng cuối trước khi sinh BDD — sót ở đây thì test sai theo).
52
+ - `CHANGED_SCOPE` — theo full/delta dưới đây.
53
+
54
+ **Chọn full vs delta** *(mặc định: lần đầu FULL, lần sau DELTA)*:
55
+ 1. Tách `--full` khỏi `$ARGUMENTS` nếu có.
56
+ 2. Kiểm tra file findings của target (tên suy ở "Phát hiện Review Mode"):
57
+ - **Không tồn tại** (lần đầu) → **FULL**: KHÔNG truyền `CHANGED_SCOPE`.
58
+ - **Tồn tại** + có `--full` → **FULL**: bỏ qua findings cũ.
59
+ - **Tồn tại** + KHÔNG `--full` → so `source_version` trong findings cũ với version target hiện tại (PRD: Metadata `Version`; BDD: `@trace.bdd_version`):
60
+ - **Bằng nhau** (target chưa đổi từ lần review trước) → DỪNG, báo: `"Target chưa đổi từ v{X} (lần review gần nhất). Không có gì để review lại — dùng --full nếu vẫn muốn quét toàn bộ."`
61
+ - **Khác** → **DELTA**: `CHANGED_SCOPE` = { `uc_id`/`section` của finding đã xử lý (status `accepted`/`modified`/`applied_automatically`) trong findings cũ } ∪ { UC có trong target hiện tại nhưng chưa từng xuất hiện ở findings cũ }.
62
+
45
63
  ---
46
64
 
47
65
  ## PRD Review Mode
@@ -52,33 +70,35 @@ Suy ra tên file findings output:
52
70
 
53
71
  Khi `setup.mode = umbrella`, PRD phải có metadata routing đúng để context-loader Bước 1.5 có thể đưa output sinh ra tới đúng service submodule. Chạy các check này **trước P1–P5**:
54
72
 
55
- **P0.1 — `@trace.domain` mặt**
56
- - Đọc block frontmatter của PRD (các dòng bắt đầu bằng `@trace.` ở đầu file)
57
- - Nếu `@trace.domain` **vắng mặt** finding **critical**:
58
- - `finding`: "`@trace.domain` đang thiếu. Umbrella routing của team dev phụ thuộc field này để đưa BDD và code output tới đúng service submodule."
59
- - `suggestion`: "Thêm `@trace.domain: {domain}` vào frontmatter của PRD. Dùng một trong các domain key được định nghĩa trong section services của `project-context.yaml` của umbrella."
73
+ > **Nguồn đọc:** PRD mang Domain/Status ở **bảng Metadata** (`| **Domain** | … |`, `| **Status** | … |`) **KHÔNG** phải frontmatter `@trace.*` (cái đó dành cho file `.feature`/tech-docs do máy đọc). Routing umbrella dựa trên Domain (bảng) + path, đúng như context-loader Bước 1.5 và `generate-bdd` (đọc `| **Status** |`).
74
+
75
+ **P0.1 Row `Domain` mặt trong Metadata**
76
+ - Đọc bảng Metadata của PRD, lấy row `| **Domain** |`.
77
+ - Nếu **vắng mặt / để trống** finding **critical**:
78
+ - `finding`: "Row `Domain` trong bảng Metadata đang thiếu. Umbrella routing của team dev phụ thuộc Domain (+ path) để đưa BDD và code output tới đúng service submodule."
79
+ - `suggestion`: "Thêm `| **Domain** | {domain} |` vào bảng Metadata. Dùng một trong các domain key được định nghĩa trong section services của `project-context.yaml` của umbrella."
60
80
  - `auto_fixable: false` — PO phải confirm tên domain đúng
61
81
 
62
- **P0.2 — `@trace.domain` khớp một service key**
63
- - Nếu `@trace.domain` có mặt, kiểm tra giá trị của nó có khớp key nào trong section `services` của project-context.yaml không
82
+ **P0.2 — `Domain` khớp một service key**
83
+ - Nếu Domain có mặt, kiểm tra giá trị của nó có khớp key nào trong section `services` của project-context.yaml không.
64
84
  - Nếu **không khớp** → finding **critical**:
65
- - `finding`: "`@trace.domain: {value}` không khớp key nào trong config `services` của umbrella. Routing sẽ fallback về path mặc định và BDD có thể được sinh sai chỗ."
66
- - `suggestion`: "Hoặc cập nhật `@trace.domain` cho khớp một service key có sẵn ({list known keys}), hoặc thêm entry mới vào `services` trong project-context.yaml cho domain `{value}`."
85
+ - `finding`: "Domain `{value}` không khớp key nào trong config `services` của umbrella. Routing sẽ fallback về path mặc định và BDD có thể được sinh sai chỗ."
86
+ - `suggestion`: "Hoặc cập nhật row Domain cho khớp một service key có sẵn ({list known keys}), hoặc thêm entry mới vào `services` trong project-context.yaml cho domain `{value}`."
67
87
  - `auto_fixable: false`
68
88
  - Nếu section `services` chưa được cấu hình (rỗng/placeholder) → finding **major**:
69
89
  - `finding`: "Section `services` của umbrella chưa được cấu hình. Không thể kiểm chứng domain routing."
70
90
  - `suggestion`: "Cập nhật section services trong `.agent/project-context.yaml` với mapping domain-to-submodule trước khi sinh BDD."
71
91
  - `auto_fixable: false`
72
92
 
73
- **P0.3 — Check `@trace.status`**
74
- - Nếu `@trace.status` vắng mặt → **minor**, `auto_fixable: true` (thêm `@trace.status: draft`)
75
- - Nếu `@trace.status: draft` → **major**, `auto_fixable: false`:
93
+ **P0.3 — Check row `Status` trong Metadata**
94
+ - Nếu row `| **Status** |` **vắng mặt** → **minor**, `auto_fixable: true` (thêm `| **Status** | draft |`)
95
+ - Nếu `Status: draft` → **major**, `auto_fixable: false`:
76
96
  - `finding`: "PRD status là `draft`. Team dev không nên sinh BDD từ một PRD chưa được duyệt."
77
- - `suggestion`: "PO/SA nên review và cập nhật status thành `approved` trước khi team dev tiếp tục."
97
+ - `suggestion`: "PO/SA nên review và cập nhật Status thành `approved` trước khi team dev tiếp tục."
78
98
 
79
99
  > **P0 là một gate check:** Nếu P0.1 hoặc P0.2 cho finding critical, hiển thị cảnh báo trước khi tiếp tục:
80
100
  > ```
81
- > ⚠️ ROUTING WARNING: phát hiện vấn đề @trace.domain.
101
+ > ⚠️ ROUTING WARNING: phát hiện vấn đề Domain trong Metadata.
82
102
  > BDD/code sinh từ PRD này có thể rơi vào sai service submodule.
83
103
  > Giải quyết các finding P0 trước khi chạy /generate-bdd.
84
104
  > ```
@@ -98,6 +118,9 @@ Quét toàn bộ PRD tìm vấn đề thuật ngữ:
98
118
  3. **Business term chưa liệt kê** — các term quan trọng vắng trong dictionary:
99
119
  → Severity: **minor**. Đề xuất thêm vào `business-dictionary.md`.
100
120
 
121
+ 4. **Thuật ngữ kỹ thuật/UI lọt vào prose nghiệp vụ** — theo baseline **Business Language Guard** (re-render, UI, timeout, spinner, API/endpoint/token…), không nằm trong dictionary nhưng vẫn là từ kỹ thuật:
122
+ → Severity: **major**, auto-fixable. `suggestion` theo guard: diễn đạt lại (Nhóm 1) / chuyển Design Spec (Nhóm 2) / bỏ về Tech Docs (Nhóm 3).
123
+
101
124
  ### P2 — Ambiguity Check
102
125
 
103
126
  Quét mỗi AC và BR tìm:
@@ -122,13 +145,20 @@ hoặc định nghĩa lại field/status transition của một entity khác đi
122
145
 
123
146
  ### P4 — Structural Completeness
124
147
 
125
- - [ ] Block Metadata: Version, Author, Date, Status
126
- - [ ] Ít nhất 1 UC với heading `#### {TICKET-ID}-UC{N}:`
127
- - [ ] Mỗi UC có: Description, Actors, Preconditions, Acceptance Criteria, Business Rules
128
- - [ ] section `## Changelog`
148
+ Đối chiếu với cấu trúc template PRD (Metadata · §1 Tổng quan · §2 AC · §3 UC · §4 UI/UX · Appendix · Change Log):
149
+
150
+ - [ ] **Metadata** có: Version, Status, Author, Created, Updated, Domain, Ticket (PO nếu có)
151
+ - [ ] **§1c "Phụ thuộc liên service"** có mặt (hoặc ghi rõ "Không có")
152
+ - [ ] **§2 Acceptance Criteria** (global) có mặt; **mỗi AC** kết thúc bằng ref `_(BR: …)_` (≥1 BR)
153
+ - [ ] **≥1 UC** với heading `#### {TICKET-ID}-UC{N}:`
154
+ - [ ] Mỗi UC có: **Actor, Description, Pre-condition, Post-condition, AC liên quan**, bảng Business Rule (AC là §2 global — UC chỉ trỏ qua "AC liên quan", KHÔNG chứa AC đầy đủ)
155
+ - [ ] **Nhất quán 2 chiều**: tập "AC liên quan" của mỗi UC = tập AC §2 có ref BR trỏ về UC đó
156
+ - [ ] **§4 UI/UX**: có User Flow và **Wireframe** (Wireframe lái coverage BDD C.1)
157
+ - [ ] **API Source nhất quán**: nếu Metadata `API Source: existing` → Appendix "Existing API Contract" đủ method/path/request/response (hoặc có block ⛔ PENDING + con trỏ nguồn); nếu greenfield/partner (API Source trống) → section "Existing API Contract" đã bị **xoá hẳn** (không để bảng rỗng)
158
+ - [ ] Có section `# Change Log`
129
159
  - [ ] Không còn giá trị `{{PLACEHOLDER}}` chưa điền
130
160
 
131
- → Section thiếu: **major**. AI có thể thêm skeleton khi `--resume` nếu được chấp nhận.
161
+ → Section/field thiếu hoặc lệch cấu trúc: **major**. AI có thể thêm skeleton khi `--resume` nếu được chấp nhận. Riêng **"Nhất quán 2 chiều"** lệch → **major**, `auto_fixable: false` (người xác nhận AC↔UC, AI không tự đoán). **API Source: existing thiếu contract** → **major**, `auto_fixable: false` (cần nguồn contract); **greenfield còn sót section "Existing API Contract" rỗng** → **minor**, `auto_fixable: true` (xoá section).
132
162
 
133
163
  ### P5 — Custom Criteria (tuỳ chọn)
134
164
 
@@ -212,6 +242,7 @@ Sau khi chạy hết các check, ghi `{paths.refinement_dir}/{slug}-review-*-fin
212
242
 
213
243
  ```yaml
214
244
  source_file: "{absolute path to reviewed file}"
245
+ source_version: "{version target lúc sinh findings — PRD: Metadata Version; BDD: @trace.bdd_version — dùng chọn full/delta lần chạy sau}"
215
246
  generated_at: "{ISO datetime}"
216
247
  review_type: "{prd | bdd}"
217
248
  status: "pending_review"
@@ -298,9 +329,12 @@ Với mỗi finding có `auto_fixable: true`, theo thứ tự (critical → majo
298
329
 
299
330
  | check_id | Áp dụng gì |
300
331
  |----------|--------------|
301
- | P0.3 (Thiếu status) | Thêm `@trace.status: draft` vào frontmatter |
332
+ | P0.3 (Thiếu status) | Thêm row `| **Status** | draft |` vào bảng Metadata |
302
333
  | P1 (Banned term) | Thay mọi lần xuất hiện banned term bằng canonical term |
303
- | P4 (Structure) | Thêm skeleton section/metadata còn thiếu |
334
+ | P1 (Thuật ngữ kỹ thuật/UI) | Diễn đạt lại theo Business Language Guard (Nhóm 1) / chuyển Design Spec (2) / bỏ về Tech Docs (3) |
335
+ | P4 (Structure) | Thêm skeleton section/metadata còn thiếu; greenfield → xoá section "Existing API Contract" rỗng |
336
+
337
+ > **Chạy Business Language Guard trên text vừa sửa TRƯỚC khi ghi** (xem section "Ngôn ngữ nghiệp vụ") — không để bản auto-fix tự kéo thuật ngữ kỹ thuật vào.
304
338
 
305
339
  **Với file BDD:**
306
340
 
@@ -372,11 +406,13 @@ Mở file findings trong Review Board → rồi chạy: /review-context --resume
372
406
 
373
407
  Áp dụng theo thứ tự: critical → major → minor.
374
408
 
409
+ > **Chạy Business Language Guard trên text vừa sửa TRƯỚC khi ghi** (xem section "Ngôn ngữ nghiệp vụ") — đặc biệt với P2 (sửa câu mơ hồ) / P4 skeleton: không để bản fix tự kéo thuật ngữ kỹ thuật-UI vào PRD.
410
+
375
411
  **Với finding PRD:**
376
412
  | check_id | Làm gì |
377
413
  |----------|-----------|
378
- | P0.3 (Thiếu status) | Thêm `@trace.status: draft` vào frontmatter |
379
- | P1 (Banned term) | Thay mọi lần xuất hiện banned term bằng canonical term |
414
+ | P0.3 (Thiếu status) | Thêm row `| **Status** | draft |` vào bảng Metadata |
415
+ | P1 (Banned term) | Thay banned term bằng canonical; thuật ngữ kỹ thuật/UI → diễn đạt lại theo Business Language Guard |
380
416
  | P2 (Ambiguity) | Áp dụng fix nêu trong `suggestion` hoặc note `modified` |
381
417
  | P3 (Conflict) | Áp dụng cách giải quyết nêu trong note modified |
382
418
  | P4 (Structure) | Thêm section/metadata field còn thiếu |
@@ -1 +1 @@
1
- 0.14.5
1
+ 0.14.6
@@ -641,7 +641,7 @@ Trước khi sinh, kiểm tra các file `.feature` có sẵn cho PRD này:
641
641
  - So với version PRD hiện tại.
642
642
  - Nếu **giống** → hỏi: "BDD đã sinh từ PRD v{version}. Gen lại? (Y/N)"
643
643
  - Nếu **khác** (PRD đã cập nhật):
644
- 1. Đọc `## Changelog` từ PRD — trích tất cả row mới hơn `@trace.prd_version` của BDD hiện có.
644
+ 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ó.
645
645
  2. Hiện CHECKPOINT:
646
646
  ```
647
647
  ⚠️ Phát hiện PRD version drift
@@ -901,7 +901,7 @@ Cập nhật `status: "applied"` ở **root level** của file findings (không
901
901
  - `| **Version** | {new_version} |`
902
902
  - `| **Updated** | {today YYYY-MM-DD} |`
903
903
  - `| **Status** | draft |` ← reset về draft, phải được duyệt lại
904
- 5. Thêm một row mới lên đầu `## Changelog` ở cuối PRD:
904
+ 5. Thêm một row mới lên đầu `# Change Log` ở cuối PRD:
905
905
  ```
906
906
  | {new_version} | {today} | {tóm tắt súc tích mọi thay đổi đã áp dụng} |
907
907
  ```
@@ -410,6 +410,47 @@ Sau khi hoàn thành tất cả các bước, bạn đã nạp:
410
410
  Tiếp tục sang bước kế tiếp của lệnh đang gọi.
411
411
 
412
412
 
413
+ ---
414
+
415
+ ## Ngôn ngữ nghiệp vụ *(áp khi viết — Fix Mode & Resume Mode)*
416
+ # Business Language Guard — chặn thuật ngữ kỹ thuật rò vào tài liệu nghiệp vụ
417
+
418
+ Tài liệu nghiệp vụ (PRD, product-definition) mô tả **WHAT** — chỉ ngôn ngữ nghiệp vụ. Guard này chạy **mỗi khi viết hoặc sửa** prose (gen mới, áp fix `--resume`, hiệu chỉnh): **quét và xử lý** các thuật ngữ kỹ thuật/UI phổ thông bên dưới **trước khi ghi**.
419
+
420
+ > Guard này là **baseline framework**, chạy **song song** với Banned Terms của `business-dictionary.md` (cơ chế dictionary giữ nguyên; project vẫn bổ sung term đặc thù vào đó). Khi cả hai cùng áp, ưu tiên bản chuẩn của dictionary nếu có.
421
+
422
+ ## Bản đồ xử lý (3 nhóm)
423
+
424
+ **Nhóm 1 — Tương tác/triển khai → DIỄN ĐẠT LẠI sang nghiệp vụ (giữ nguyên nghĩa):**
425
+
426
+ | Kỹ thuật/UI | Cách nói nghiệp vụ |
427
+ |---|---|
428
+ | re-render / render lại / reload / refresh (màn) | "hiển thị lại {tên màn}" |
429
+ | timeout | "quá thời gian chờ" |
430
+ | lỗi mạng / network error | "lỗi kết nối" |
431
+ | UI / giao diện (khi chỉ một màn) | "màn" / "màn hình" |
432
+ | click / tap | "bấm" / "chọn" |
433
+ | popup / modal (nếu chỉ là khái niệm hiển thị) | "hộp thoại" / "thông báo" |
434
+ | disable / enable (nút) | "khoá" / "mở" thao tác |
435
+ | redirect / navigate | "chuyển tới {màn}" |
436
+
437
+ **Nhóm 2 — Visual thuần → CHUYỂN Design Spec (bỏ khỏi PRD, ghi nhận lại):**
438
+ `spinner`, `loading indicator`, `animation`, `fade/slide`, màu sắc, font, layout pixel, micro-interaction → *"Chi tiết visual này thuộc Design Spec — ghi nhận để tạo Design Spec sau."*
439
+
440
+ **Nhóm 3 — Backend/contract thuần → BỎ khỏi PRD (thuộc Tech Docs):**
441
+ `API`, `endpoint`, `token/JWT`, `HTTP status`, tên class/bảng/cột DB, query, payload, header.
442
+ *(Ngoại lệ DUY NHẤT: Appendix "Existing API Contract" khi `API Source: existing` — xem Platform Strategy.)*
443
+
444
+ ## Quy tắc áp dụng
445
+ - Quét toàn bộ text sắp ghi (User Story, AC, BR, Business Logic, Scope, Edge Cases, Assumptions…).
446
+ - Nhóm 1 → thay tại chỗ, giữ nguyên nghĩa nghiệp vụ. **Đồng bộ cách diễn đạt** với chỗ đã có sẵn trong cùng tài liệu (vd nếu "quá thời gian chờ" đã dùng ở một BR → dùng nhất quán ở mọi nơi).
447
+ - Nhóm 2 → gỡ khỏi prose nghiệp vụ + nhắc chuyển Design Spec.
448
+ - Nhóm 3 → gỡ khỏi PRD (trừ ngoại lệ brownfield).
449
+ - Nếu term không có trong bản đồ nhưng rõ ràng là tên kỹ thuật/triển khai → vẫn diễn đạt lại theo tinh thần Nhóm 1, đừng để lọt.
450
+
451
+ **Checklist (dùng ở Quality Checklist của lệnh):** 0 thuật ngữ kỹ thuật/UI (re-render, UI, timeout, spinner, API/endpoint/token…) trong prose nghiệp vụ — đã diễn đạt lại (Nhóm 1) / chuyển Design Spec (Nhóm 2) / bỏ về Tech Docs (Nhóm 3).
452
+
453
+
413
454
  ---
414
455
 
415
456
  ## Phát hiện Review Mode
@@ -589,6 +630,19 @@ Convergence: {convergence_rounds} vòng critic — file findings đã đầy đ
589
630
  - **Check do orchestrator chạy (không fan out):** `P0` (umbrella routing) và `P3` (xung đột cross-PRD) cần config / context của PRD khác — orchestrator tự chạy chúng **trước** fan-out và thêm kết quả vào `ALL_FINDINGS`.
590
631
  - Vòng lặp completeness-critic (Phase 2) đảm bảo file findings đầy đủ trong một lần chạy — chạy lại `/review-context` sẽ lòi ra **0 finding mới**. Map mỗi dimension vào field `check_id` của schema dưới đây.
591
632
 
633
+ **Tham số truyền vào Quy trình Review:**
634
+ - `GRANULARITY = per-uc` — LUÔN fan-out theo từng UC (bỏ ngưỡng cả-file), để **cổng review bắt đủ lỗi ngay lần đầu** (cổng cuối trước khi sinh BDD — sót ở đây thì test sai theo).
635
+ - `CHANGED_SCOPE` — theo full/delta dưới đây.
636
+
637
+ **Chọn full vs delta** *(mặc định: lần đầu FULL, lần sau DELTA)*:
638
+ 1. Tách `--full` khỏi `$ARGUMENTS` nếu có.
639
+ 2. Kiểm tra file findings của target (tên suy ở "Phát hiện Review Mode"):
640
+ - **Không tồn tại** (lần đầu) → **FULL**: KHÔNG truyền `CHANGED_SCOPE`.
641
+ - **Tồn tại** + có `--full` → **FULL**: bỏ qua findings cũ.
642
+ - **Tồn tại** + KHÔNG `--full` → so `source_version` trong findings cũ với version target hiện tại (PRD: Metadata `Version`; BDD: `@trace.bdd_version`):
643
+ - **Bằng nhau** (target chưa đổi từ lần review trước) → DỪNG, báo: `"Target chưa đổi từ v{X} (lần review gần nhất). Không có gì để review lại — dùng --full nếu vẫn muốn quét toàn bộ."`
644
+ - **Khác** → **DELTA**: `CHANGED_SCOPE` = { `uc_id`/`section` của finding đã xử lý (status `accepted`/`modified`/`applied_automatically`) trong findings cũ } ∪ { UC có trong target hiện tại nhưng chưa từng xuất hiện ở findings cũ }.
645
+
592
646
  ---
593
647
 
594
648
  ## PRD Review Mode
@@ -599,33 +653,35 @@ Convergence: {convergence_rounds} vòng critic — file findings đã đầy đ
599
653
 
600
654
  Khi `setup.mode = umbrella`, PRD phải có metadata routing đúng để context-loader Bước 1.5 có thể đưa output sinh ra tới đúng service submodule. Chạy các check này **trước P1–P5**:
601
655
 
602
- **P0.1 — `@trace.domain` mặt**
603
- - Đọc block frontmatter của PRD (các dòng bắt đầu bằng `@trace.` ở đầu file)
604
- - Nếu `@trace.domain` **vắng mặt** finding **critical**:
605
- - `finding`: "`@trace.domain` đang thiếu. Umbrella routing của team dev phụ thuộc field này để đưa BDD và code output tới đúng service submodule."
606
- - `suggestion`: "Thêm `@trace.domain: {domain}` vào frontmatter của PRD. Dùng một trong các domain key được định nghĩa trong section services của `project-context.yaml` của umbrella."
656
+ > **Nguồn đọc:** PRD mang Domain/Status ở **bảng Metadata** (`| **Domain** | … |`, `| **Status** | … |`) **KHÔNG** phải frontmatter `@trace.*` (cái đó dành cho file `.feature`/tech-docs do máy đọc). Routing umbrella dựa trên Domain (bảng) + path, đúng như context-loader Bước 1.5 và `generate-bdd` (đọc `| **Status** |`).
657
+
658
+ **P0.1 Row `Domain` mặt trong Metadata**
659
+ - Đọc bảng Metadata của PRD, lấy row `| **Domain** |`.
660
+ - Nếu **vắng mặt / để trống** finding **critical**:
661
+ - `finding`: "Row `Domain` trong bảng Metadata đang thiếu. Umbrella routing của team dev phụ thuộc Domain (+ path) để đưa BDD và code output tới đúng service submodule."
662
+ - `suggestion`: "Thêm `| **Domain** | {domain} |` vào bảng Metadata. Dùng một trong các domain key được định nghĩa trong section services của `project-context.yaml` của umbrella."
607
663
  - `auto_fixable: false` — PO phải confirm tên domain đúng
608
664
 
609
- **P0.2 — `@trace.domain` khớp một service key**
610
- - Nếu `@trace.domain` có mặt, kiểm tra giá trị của nó có khớp key nào trong section `services` của project-context.yaml không
665
+ **P0.2 — `Domain` khớp một service key**
666
+ - Nếu Domain có mặt, kiểm tra giá trị của nó có khớp key nào trong section `services` của project-context.yaml không.
611
667
  - Nếu **không khớp** → finding **critical**:
612
- - `finding`: "`@trace.domain: {value}` không khớp key nào trong config `services` của umbrella. Routing sẽ fallback về path mặc định và BDD có thể được sinh sai chỗ."
613
- - `suggestion`: "Hoặc cập nhật `@trace.domain` cho khớp một service key có sẵn ({list known keys}), hoặc thêm entry mới vào `services` trong project-context.yaml cho domain `{value}`."
668
+ - `finding`: "Domain `{value}` không khớp key nào trong config `services` của umbrella. Routing sẽ fallback về path mặc định và BDD có thể được sinh sai chỗ."
669
+ - `suggestion`: "Hoặc cập nhật row Domain cho khớp một service key có sẵn ({list known keys}), hoặc thêm entry mới vào `services` trong project-context.yaml cho domain `{value}`."
614
670
  - `auto_fixable: false`
615
671
  - Nếu section `services` chưa được cấu hình (rỗng/placeholder) → finding **major**:
616
672
  - `finding`: "Section `services` của umbrella chưa được cấu hình. Không thể kiểm chứng domain routing."
617
673
  - `suggestion`: "Cập nhật section services trong `.agent/project-context.yaml` với mapping domain-to-submodule trước khi sinh BDD."
618
674
  - `auto_fixable: false`
619
675
 
620
- **P0.3 — Check `@trace.status`**
621
- - Nếu `@trace.status` vắng mặt → **minor**, `auto_fixable: true` (thêm `@trace.status: draft`)
622
- - Nếu `@trace.status: draft` → **major**, `auto_fixable: false`:
676
+ **P0.3 — Check row `Status` trong Metadata**
677
+ - Nếu row `| **Status** |` **vắng mặt** → **minor**, `auto_fixable: true` (thêm `| **Status** | draft |`)
678
+ - Nếu `Status: draft` → **major**, `auto_fixable: false`:
623
679
  - `finding`: "PRD status là `draft`. Team dev không nên sinh BDD từ một PRD chưa được duyệt."
624
- - `suggestion`: "PO/SA nên review và cập nhật status thành `approved` trước khi team dev tiếp tục."
680
+ - `suggestion`: "PO/SA nên review và cập nhật Status thành `approved` trước khi team dev tiếp tục."
625
681
 
626
682
  > **P0 là một gate check:** Nếu P0.1 hoặc P0.2 cho finding critical, hiển thị cảnh báo trước khi tiếp tục:
627
683
  > ```
628
- > ⚠️ ROUTING WARNING: phát hiện vấn đề @trace.domain.
684
+ > ⚠️ ROUTING WARNING: phát hiện vấn đề Domain trong Metadata.
629
685
  > BDD/code sinh từ PRD này có thể rơi vào sai service submodule.
630
686
  > Giải quyết các finding P0 trước khi chạy /generate-bdd.
631
687
  > ```
@@ -645,6 +701,9 @@ Quét toàn bộ PRD tìm vấn đề thuật ngữ:
645
701
  3. **Business term chưa liệt kê** — các term quan trọng vắng trong dictionary:
646
702
  → Severity: **minor**. Đề xuất thêm vào `business-dictionary.md`.
647
703
 
704
+ 4. **Thuật ngữ kỹ thuật/UI lọt vào prose nghiệp vụ** — theo baseline **Business Language Guard** (re-render, UI, timeout, spinner, API/endpoint/token…), không nằm trong dictionary nhưng vẫn là từ kỹ thuật:
705
+ → Severity: **major**, auto-fixable. `suggestion` theo guard: diễn đạt lại (Nhóm 1) / chuyển Design Spec (Nhóm 2) / bỏ về Tech Docs (Nhóm 3).
706
+
648
707
  ### P2 — Ambiguity Check
649
708
 
650
709
  Quét mỗi AC và BR tìm:
@@ -669,13 +728,20 @@ hoặc định nghĩa lại field/status transition của một entity khác đi
669
728
 
670
729
  ### P4 — Structural Completeness
671
730
 
672
- - [ ] Block Metadata: Version, Author, Date, Status
673
- - [ ] Ít nhất 1 UC với heading `#### {TICKET-ID}-UC{N}:`
674
- - [ ] Mỗi UC có: Description, Actors, Preconditions, Acceptance Criteria, Business Rules
675
- - [ ] section `## Changelog`
731
+ Đối chiếu với cấu trúc template PRD (Metadata · §1 Tổng quan · §2 AC · §3 UC · §4 UI/UX · Appendix · Change Log):
732
+
733
+ - [ ] **Metadata** có: Version, Status, Author, Created, Updated, Domain, Ticket (PO nếu có)
734
+ - [ ] **§1c "Phụ thuộc liên service"** có mặt (hoặc ghi rõ "Không có")
735
+ - [ ] **§2 Acceptance Criteria** (global) có mặt; **mỗi AC** kết thúc bằng ref `_(BR: …)_` (≥1 BR)
736
+ - [ ] **≥1 UC** với heading `#### {TICKET-ID}-UC{N}:`
737
+ - [ ] Mỗi UC có: **Actor, Description, Pre-condition, Post-condition, AC liên quan**, bảng Business Rule (AC là §2 global — UC chỉ trỏ qua "AC liên quan", KHÔNG chứa AC đầy đủ)
738
+ - [ ] **Nhất quán 2 chiều**: tập "AC liên quan" của mỗi UC = tập AC §2 có ref BR trỏ về UC đó
739
+ - [ ] **§4 UI/UX**: có User Flow và **Wireframe** (Wireframe lái coverage BDD C.1)
740
+ - [ ] **API Source nhất quán**: nếu Metadata `API Source: existing` → Appendix "Existing API Contract" đủ method/path/request/response (hoặc có block ⛔ PENDING + con trỏ nguồn); nếu greenfield/partner (API Source trống) → section "Existing API Contract" đã bị **xoá hẳn** (không để bảng rỗng)
741
+ - [ ] Có section `# Change Log`
676
742
  - [ ] Không còn giá trị `{{PLACEHOLDER}}` chưa điền
677
743
 
678
- → Section thiếu: **major**. AI có thể thêm skeleton khi `--resume` nếu được chấp nhận.
744
+ → Section/field thiếu hoặc lệch cấu trúc: **major**. AI có thể thêm skeleton khi `--resume` nếu được chấp nhận. Riêng **"Nhất quán 2 chiều"** lệch → **major**, `auto_fixable: false` (người xác nhận AC↔UC, AI không tự đoán). **API Source: existing thiếu contract** → **major**, `auto_fixable: false` (cần nguồn contract); **greenfield còn sót section "Existing API Contract" rỗng** → **minor**, `auto_fixable: true` (xoá section).
679
745
 
680
746
  ### P5 — Custom Criteria (tuỳ chọn)
681
747
 
@@ -759,6 +825,7 @@ Sau khi chạy hết các check, ghi `{paths.refinement_dir}/{slug}-review-*-fin
759
825
 
760
826
  ```yaml
761
827
  source_file: "{absolute path to reviewed file}"
828
+ source_version: "{version target lúc sinh findings — PRD: Metadata Version; BDD: @trace.bdd_version — dùng chọn full/delta lần chạy sau}"
762
829
  generated_at: "{ISO datetime}"
763
830
  review_type: "{prd | bdd}"
764
831
  status: "pending_review"
@@ -945,9 +1012,12 @@ Với mỗi finding có `auto_fixable: true`, theo thứ tự (critical → majo
945
1012
 
946
1013
  | check_id | Áp dụng gì |
947
1014
  |----------|--------------|
948
- | P0.3 (Thiếu status) | Thêm `@trace.status: draft` vào frontmatter |
1015
+ | P0.3 (Thiếu status) | Thêm row `| **Status** | draft |` vào bảng Metadata |
949
1016
  | P1 (Banned term) | Thay mọi lần xuất hiện banned term bằng canonical term |
950
- | P4 (Structure) | Thêm skeleton section/metadata còn thiếu |
1017
+ | P1 (Thuật ngữ kỹ thuật/UI) | Diễn đạt lại theo Business Language Guard (Nhóm 1) / chuyển Design Spec (2) / bỏ về Tech Docs (3) |
1018
+ | P4 (Structure) | Thêm skeleton section/metadata còn thiếu; greenfield → xoá section "Existing API Contract" rỗng |
1019
+
1020
+ > **Chạy Business Language Guard trên text vừa sửa TRƯỚC khi ghi** (xem section "Ngôn ngữ nghiệp vụ") — không để bản auto-fix tự kéo thuật ngữ kỹ thuật vào.
951
1021
 
952
1022
  **Với file BDD:**
953
1023
 
@@ -1019,11 +1089,13 @@ Mở file findings trong Review Board → rồi chạy: /review-context --resume
1019
1089
 
1020
1090
  Áp dụng theo thứ tự: critical → major → minor.
1021
1091
 
1092
+ > **Chạy Business Language Guard trên text vừa sửa TRƯỚC khi ghi** (xem section "Ngôn ngữ nghiệp vụ") — đặc biệt với P2 (sửa câu mơ hồ) / P4 skeleton: không để bản fix tự kéo thuật ngữ kỹ thuật-UI vào PRD.
1093
+
1022
1094
  **Với finding PRD:**
1023
1095
  | check_id | Làm gì |
1024
1096
  |----------|-----------|
1025
- | P0.3 (Thiếu status) | Thêm `@trace.status: draft` vào frontmatter |
1026
- | P1 (Banned term) | Thay mọi lần xuất hiện banned term bằng canonical term |
1097
+ | P0.3 (Thiếu status) | Thêm row `| **Status** | draft |` vào bảng Metadata |
1098
+ | P1 (Banned term) | Thay banned term bằng canonical; thuật ngữ kỹ thuật/UI → diễn đạt lại theo Business Language Guard |
1027
1099
  | P2 (Ambiguity) | Áp dụng fix nêu trong `suggestion` hoặc note `modified` |
1028
1100
  | P3 (Conflict) | Áp dụng cách giải quyết nêu trong note modified |
1029
1101
  | P4 (Structure) | Thêm section/metadata field còn thiếu |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edupia-tutor/spec-driven-docs",
3
- "version": "0.14.5",
3
+ "version": "0.14.6",
4
4
  "description": "AI-First Spec-Driven Development workflow framework for Claude Code",
5
5
  "bin": {
6
6
  "spec-driven-docs": "./bin/index.js"