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

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.
Files changed (82) hide show
  1. package/commands/debug.md +1 -0
  2. package/commands/define-product.md +70 -5
  3. package/commands/define-product.tmpl +33 -5
  4. package/commands/dev-gen-test.md +1 -0
  5. package/commands/dev-run-test.md +1 -0
  6. package/commands/dev-smoke-test.md +1 -0
  7. package/commands/fix-bug.md +1 -0
  8. package/commands/generate-bdd.md +15 -11
  9. package/commands/generate-bdd.tmpl +14 -11
  10. package/commands/generate-code.md +1 -0
  11. package/commands/generate-design-spec.md +1 -0
  12. package/commands/generate-prd.md +111 -10
  13. package/commands/generate-prd.tmpl +61 -7
  14. package/commands/generate-spec-manifest.md +1 -0
  15. package/commands/generate-tech-docs.md +1 -0
  16. package/commands/learn.md +1 -0
  17. package/commands/map-testids.md +1 -0
  18. package/commands/propose-scenario.md +1 -0
  19. package/commands/qc-analyze.md +1 -0
  20. package/commands/qc-design-test.md +1 -0
  21. package/commands/qc-plan.md +1 -0
  22. package/commands/qc-report.md +1 -0
  23. package/commands/qc-review.md +1 -0
  24. package/commands/qc-run-test.md +1 -0
  25. package/commands/refine-prd.md +172 -18
  26. package/commands/refine-prd.tmpl +114 -13
  27. package/commands/report-bug.md +1 -0
  28. package/commands/review-code.md +1 -0
  29. package/commands/review-context.md +22 -5
  30. package/commands/review-tech-docs.md +1 -0
  31. package/commands/setup-ai-first.md +1 -0
  32. package/commands/validate-traces.md +1 -0
  33. package/core/FRAMEWORK_VERSION +1 -1
  34. package/core/commands/debug.md +1 -0
  35. package/core/commands/define-product.md +70 -5
  36. package/core/commands/dev-gen-test.md +1 -0
  37. package/core/commands/dev-run-test.md +1 -0
  38. package/core/commands/dev-smoke-test.md +1 -0
  39. package/core/commands/fix-bug.md +1 -0
  40. package/core/commands/generate-bdd.md +15 -11
  41. package/core/commands/generate-code.md +1 -0
  42. package/core/commands/generate-design-spec.md +1 -0
  43. package/core/commands/generate-prd.md +111 -10
  44. package/core/commands/generate-spec-manifest.md +1 -0
  45. package/core/commands/generate-tech-docs.md +1 -0
  46. package/core/commands/learn.md +1 -0
  47. package/core/commands/map-testids.md +1 -0
  48. package/core/commands/propose-scenario.md +1 -0
  49. package/core/commands/qc-analyze.md +1 -0
  50. package/core/commands/qc-design-test.md +1 -0
  51. package/core/commands/qc-plan.md +1 -0
  52. package/core/commands/qc-report.md +1 -0
  53. package/core/commands/qc-review.md +1 -0
  54. package/core/commands/qc-run-test.md +1 -0
  55. package/core/commands/refine-prd.md +172 -18
  56. package/core/commands/report-bug.md +1 -0
  57. package/core/commands/review-code.md +1 -0
  58. package/core/commands/review-context.md +22 -5
  59. package/core/commands/review-tech-docs.md +1 -0
  60. package/core/commands/setup-ai-first.md +1 -0
  61. package/core/commands/validate-traces.md +1 -0
  62. package/core/skills/code/SKILL.md +1 -0
  63. package/core/skills/design-spec/SKILL.md +1 -0
  64. package/core/skills/prd/SKILL.md +14 -3
  65. package/core/skills/spec/SKILL.md +1 -0
  66. package/core/skills/test/SKILL.md +1 -0
  67. package/core/steps/business-language.md +36 -0
  68. package/core/steps/gate.md +1 -0
  69. package/core/steps/review-fanout.md +21 -5
  70. package/core/templates/prd.template.md +13 -3
  71. package/core/templates/product-definition.template.md +8 -1
  72. package/package.json +1 -1
  73. package/skills/code/SKILL.md +1 -0
  74. package/skills/design-spec/SKILL.md +1 -0
  75. package/skills/prd/SKILL.md +14 -3
  76. package/skills/spec/SKILL.md +1 -0
  77. package/skills/test/SKILL.md +1 -0
  78. package/steps/business-language.md +36 -0
  79. package/steps/gate.md +1 -0
  80. package/steps/review-fanout.md +21 -5
  81. package/templates/prd.template.md +13 -3
  82. package/templates/product-definition.template.md +8 -1
@@ -5,11 +5,29 @@
5
5
 
6
6
  *Lưu ý: Với lệnh này, target file ở Bước 1 là một file PRD (`{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder) dưới `{paths.specs_dir}/{domain}/{prd-slug}/`. Đọc toàn bộ PRD sau khi phân giải file.*
7
7
 
8
+ ### Bước 0-C — Resume mode routing *(riêng /refine-prd, chạy ngay sau Bước 0 của Gate)*
9
+
10
+ Nếu `$ARGUMENTS` chứa `--resume`:
11
+ - Tách `--resume` ra, phần còn lại là `raw_target` (file path hoặc prd-slug).
12
+ - **Nạp minimal context:** đọc `.agent/project-context.yaml`, trích xuất `paths.refinement_dir`
13
+ (default: `.agent/review` nếu không có hoặc file không tồn tại).
14
+ - Chạy **Bước 1** với `raw_target` để phân giải `prd-slug` và `target_file`.
15
+ Nếu `raw_target` rỗng → liệt kê các file `*.yaml` trong `{paths.refinement_dir}/` và hỏi user chọn findings file nào.
16
+ - **Bỏ qua Bước 0-B, 2, 3** — apply findings là tác vụ cơ học, không cần model check hay load full context.
17
+ - → Nhảy thẳng tới **Resume Mode** ở cuối lệnh này.
18
+
19
+ Nếu `$ARGUMENTS` không chứa `--resume` → tiếp tục luồng review bình thường bên dưới.
20
+
8
21
  ## Context
9
22
  {{include:steps/context-loader.md}}
10
23
 
11
24
  ---
12
25
 
26
+ ## Ngôn ngữ nghiệp vụ *(áp khi viết/áp fix — gồm cả Resume Mode Phase 2)*
27
+ {{include:steps/business-language.md}}
28
+
29
+ ---
30
+
13
31
  ## Quy trình Review
14
32
  {{include:steps/review-fanout.md}}
15
33
 
@@ -19,6 +37,19 @@
19
37
 
20
38
  Chạy review qua **Quy trình Review** ở trên (`steps/review-fanout.md`).
21
39
 
40
+ **Tham số truyền vào Quy trình Review:**
41
+ - `GRANULARITY = per-uc` — LUÔN fan-out theo từng UC (bỏ ngưỡng cả-file), để **ngay lần đầu đã lòi phần nhiều issue**, không dồn sang lần sau.
42
+ - `CHANGED_SCOPE` — xác định theo chế độ full/delta ngay dưới đây.
43
+
44
+ **Chọn full vs delta** *(mặc định: lần đầu FULL, lần sau DELTA)*:
45
+ 1. Tách `--full` khỏi `$ARGUMENTS` nếu có.
46
+ 2. Kiểm tra `{paths.refinement_dir}/{prd-slug}-findings.yaml`:
47
+ - **Không tồn tại** (lần đầu review PRD này) → **FULL**: KHÔNG truyền `CHANGED_SCOPE`.
48
+ - **Tồn tại** + có `--full` → **FULL**: bỏ qua findings cũ, không truyền `CHANGED_SCOPE` (ép quét lại toàn bộ).
49
+ - **Tồn tại** + KHÔNG có `--full` → so `prd_version` trong findings cũ với `| **Version** |` của PRD hiện tại:
50
+ - **Bằng nhau** (PRD chưa đổi từ lần review trước) → DỪNG, báo: `"PRD 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ộ."`
51
+ - **Khác** (đã có `--resume` bump version) → **DELTA**: `CHANGED_SCOPE` = { `uc_id`/`section` của các finding `status: applied` trong findings cũ } ∪ { UC có trong PRD hiện tại nhưng chưa từng xuất hiện ở findings cũ }. Truyền `CHANGED_SCOPE` này vào Quy trình Review.
52
+
22
53
  **DIMENSIONS** = 4 lăng kính dưới đây — fan out một sub-agent cho mỗi lăng kính, mỗi cái quét
23
54
  toàn bộ PRD qua đúng lăng kính của nó:
24
55
 
@@ -37,10 +68,18 @@ Suy ra tên file output từ PRD slug:
37
68
  - File PRD: `{paths.specs_dir}/payment/create-invoice/PAY01-create-invoice.md` → output: `{paths.refinement_dir}/create-invoice-findings.yaml`
38
69
  - Quy tắc: lấy tên folder cha của PRD (prd-slug), thêm hậu tố `-findings.yaml`
39
70
 
71
+ Trước khi ghi file, xác định `recommendation` từ findings đã dedup và sắp xếp:
72
+ - `by_severity.critical ≥ 1` → `BLOCKED`
73
+ - `by_severity.critical = 0` và `by_severity.major ≥ 1` → `NEEDS_REVISION`
74
+ - `by_severity.critical = 0` và `by_severity.major = 0` → `APPROVED_WITH_MINOR_CHANGES`
75
+
76
+ Đảm bảo `{paths.refinement_dir}/` tồn tại — tạo thư mục nếu chưa có trước khi ghi file.
77
+
40
78
  Ghi `{paths.refinement_dir}/{prd-slug}-findings.yaml`:
41
79
 
42
80
  ```yaml
43
81
  prd_source: "{paths.specs_dir}/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md"
82
+ prd_version: "{đọc | **Version** | từ metadata PRD lúc sinh findings — dùng để chọn full/delta lần chạy sau}"
44
83
  generated_at: "{ISO datetime}"
45
84
  status: "pending_review"
46
85
 
@@ -53,14 +92,32 @@ findings:
53
92
  quote: "{trích đoạn nguyên văn copy CHÍNH XÁC từ PRD tại vị trí lỗi, ≤120 ký tự}"
54
93
  finding: "{mô tả gap hoặc vấn đề}"
55
94
  suggestion: "{đề xuất cải thiện cụ thể, hành động được}"
56
- auto_fixable: false # true = AI áp dụng khi --resume; false = người phải ghi quyết định trong note
57
- status: "pending" # pending | accepted | rejected | needs_discussion
95
+ resolution_edge_cases: # CHỈ điền cho critical/major; minor để [] (bỏ qua)
96
+ # Phân tích bậc-hai (advisory, KHÔNG chặn): nếu áp `suggestion` này thì thể đẻ ra
97
+ # edge case / side-effect gì — path lỗi mới, va chạm với BR/UC khác, trạng thái biên,
98
+ # hệ luỵ cross-section. PO đọc để cân nhắc trước khi accept; nếu muốn xử lý → tạo finding mới.
99
+ - "{edge case có thể phát sinh nếu chốt phương án này}"
100
+ auto_fixable: false
101
+ # true = AI tự tin cao vào suggestion này; Review Board có thể hiển thị nút "quick accept"
102
+ # false = cần human đọc kỹ và ghi quyết định trước khi accept
103
+ # Resume Mode luôn áp dụng theo status (accepted|modified), bất kể auto_fixable.
104
+ status: "pending"
105
+ # Lifecycle finding-level:
106
+ # pending → finding mới, chưa được review
107
+ # accepted → reviewer chấp nhận suggestion gốc → Resume sẽ apply
108
+ # modified → reviewer đã sửa suggestion trong Review Board → Resume dùng suggestion đã sửa
109
+ # rejected → reviewer bác bỏ, không apply
110
+ # needs_discussion → hai suggestion xung đột, cần con người quyết định trước khi --resume
111
+ # applied → đã được Resume Mode apply vào PRD
58
112
 
59
113
  summary:
60
114
  total_findings: {N}
61
115
  by_severity: { critical: {N}, major: {N}, minor: {N} }
62
116
  by_lens: { QA: {N}, DEV: {N}, SA: {N}, PO: {N} }
63
117
  recommendation: "APPROVED_WITH_MINOR_CHANGES | NEEDS_REVISION | BLOCKED"
118
+ # Rule: critical ≥ 1 → BLOCKED
119
+ # critical = 0, major ≥ 1 → NEEDS_REVISION
120
+ # critical = 0, major = 0 → APPROVED_WITH_MINOR_CHANGES
64
121
  ```
65
122
 
66
123
  > **Field định vị (`quote` + `uc_id`) — bắt buộc cho source-jump của Review Board.**
@@ -69,36 +126,76 @@ summary:
69
126
  > `uc_id` là Use Case sở hữu (hoặc `""` cho finding PRD-global). Hai field này cho phép reviewer click một
70
127
  > finding trong Review Board và nhảy thẳng tới đúng vị trí trong PRD nguồn.
71
128
 
129
+ > **`resolution_edge_cases` — phân tích bậc-hai (chỉ critical/major).**
130
+ > Với mỗi finding `critical`/`major`, sau khi viết `suggestion`, nghĩ tiếp: *nếu PO chốt phương án này thì
131
+ > đẻ ra edge case / side-effect gì?* (path lỗi mới, va chạm BR/UC khác, trạng thái biên, hệ luỵ cross-section).
132
+ > Ghi vào `resolution_edge_cases` để PO **thấy trước khi accept**. Đây là **advisory** — KHÔNG chặn, KHÔNG tự
133
+ > tạo finding; PO đọc rồi quyết. Finding `minor` → để `[]`.
134
+ > *(Phần phản hồi cho phương án PO **tự sửa** (`modified`) đến ở vòng sau: sau `--resume`, lần `/refine-prd`
135
+ > kế chạy delta sẽ quét lại UC đã đổi + critic toàn-doc → tự lòi edge case mà phương án đó tạo ra.)*
136
+
72
137
  ## Report
73
138
 
74
139
  {{include:steps/report-footer.md}}
75
140
 
141
+ Dùng footer chuẩn với hai field bổ sung `Findings` và `Review` đặt ngay sau `Status`:
142
+
143
+ ```
144
+ ---
145
+ Status : {badge}
146
+ Findings : {total} | 🔴 Critical: {N} | 🟡 Major: {N} | 🟢 Minor: {N}
147
+ Review : {paths.refinement_dir}/{prd-slug}-findings.yaml
148
+ Output Artifacts:
149
+ created {paths.refinement_dir}/{prd-slug}-findings.yaml (findings từ 4-lens review)
150
+ Pipeline : Discovery → [PRD ◀ bạn ở đây] → Design Spec → BDD → Tech Design → Code → Dev Self-Check → QC → Trace Audit
151
+ Vòng review: [① phân tích ◀] → ② Review Board → ③ --resume
152
+ Next : Mở trong Review Board (chuột phải vào file) → Cập nhật PRD
153
+ → /review-context {prd-file} ← kiểm tra chất lượng PRD trước khi sinh BDD
154
+ → /generate-bdd {prd-file}
155
+ ```
156
+
157
+ Nếu có finding nào có `status: "needs_discussion"`, thêm warning block sau footer:
158
+
76
159
  ```
77
- /refine-prd Hoàn tất {PRD name}
78
- Findings: {total} | 🔴 Critical: {N} | 🟡 Major: {N} | 🟢 Minor: {N}
79
- Review: {paths.refinement_dir}/{prd-slug}-findings.yaml
80
- Next: Mở trong Review Board (chuột phải vào file) → Cập nhật PRD
81
- /review-context {prd-file} ← kiểm tra chất lượng PRD trước khi sinh BDD
82
- /generate-bdd {prd-file}
160
+ ⚠️ {N} finding(s) cần quyết định của bạn trước khi --resume:
161
+ Mở {paths.refinement_dir}/{prd-slug}-findings.yaml
162
+ Với mỗi finding có status "needs_discussion":
163
+ 1. Đọc cả hai phương án trong `suggestion`
164
+ 2. Chọn một (hoặc viết phương án khác) vào `suggestion`
165
+ 3. Đổi `status` "accepted"
166
+ Sau đó chạy: /refine-prd {prd-file} --resume
83
167
  ```
168
+ *(Bỏ warning block này nếu không có `needs_discussion` finding nào.)*
84
169
 
85
170
  ---
86
171
 
87
172
  ## Resume Mode — Áp dụng Findings & Bump Version
88
173
 
89
- *Kích hoạt khi `$ARGUMENTS` chứa `--resume` (gọi bởi nút "Apply to PRD" của Review Board).*
174
+ *Được route tới từ Bước 0-C — Resume mode routing. `prd-slug` `target_file` đã được phân giải Bước 1 trước khi nhảy vào đây.*
90
175
 
91
176
  ### Phase 1 — Đọc các finding được chấp nhận
92
177
 
93
- 1. Đọc `{paths.refinement_dir}/{prd-slug}-findings.yaml`.
94
- 2. Gom tất cả finding `status: "accepted"` hoặc `status: "modified"`.
95
- 3. Nếu không có finding nào được chấp nhận → báo "No accepted findings. PRD unchanged." và dừng.
178
+ 1. Kiểm tra `{paths.refinement_dir}/{prd-slug}-findings.yaml` có tồn tại không.
179
+ Nếu không báo lỗi ràng dừng:
180
+ ```
181
+ ❌ Không tìm thấy findings file tại {paths.refinement_dir}/{prd-slug}-findings.yaml
182
+ Hãy chạy /refine-prd {prd-file} trước để tạo findings, rồi mới --resume.
183
+ ```
184
+ 2. Đọc file findings.
185
+ 3. Gom tất cả finding có `status: "accepted"` hoặc `status: "modified"`.
186
+ 4. Nếu không có finding nào được chấp nhận → báo "No accepted findings. PRD unchanged." và dừng.
187
+ 5. Nếu còn finding nào có `status: "needs_discussion"` → cảnh báo (không dừng):
188
+ ```
189
+ ⚠️ {N} finding(s) chưa được giải quyết (needs_discussion) — sẽ bị bỏ qua lần apply này.
190
+ Giải quyết chúng trong Review Board rồi chạy lại --resume để apply.
191
+ ```
96
192
 
97
193
  ### Phase 2 — Áp dụng thay đổi vào PRD
98
194
 
99
195
  Với mỗi finding được chấp nhận, theo thứ tự severity (critical → major → minor):
100
196
  - Đi tới section PRD được chỉ định bởi `finding.section`.
101
197
  - Áp dụng `finding.suggestion`. Với finding `status: "modified"`, người đã sửa sẵn `finding.suggestion` trong Review Board — giá trị đã sửa đó CHÍNH LÀ bản fix cần áp dụng.
198
+ - **Chạy Business Language Guard trên text mới TRƯỚC khi ghi** (xem section "Ngôn ngữ nghiệp vụ"): diễn đạt lại / gỡ thuật ngữ kỹ thuật-UI để fix không tự kéo theo term kỹ thuật vào PRD.
102
199
  - Không thay đổi bất kỳ section nào không được tham chiếu bởi một finding được chấp nhận.
103
200
 
104
201
  ### Phase 2.5 — Cập nhật file findings
@@ -106,7 +203,9 @@ Với mỗi finding được chấp nhận, theo thứ tự severity (critical
106
203
  Với mỗi finding đã áp dụng (status là `accepted` hoặc `modified`):
107
204
  - Đặt `status: "applied"` trong `{paths.refinement_dir}/{prd-slug}-findings.yaml`.
108
205
 
109
- Cập nhật `summary.status: "applied"` trong file findings.
206
+ Cập nhật `status: "applied"` **root level** của file findings (không phải `summary.status`).
207
+ # Lifecycle file-level: pending_review → applied | partially_applied
208
+ # partially_applied khi có finding bị rejected hoặc needs_discussion còn sót lại.
110
209
 
111
210
  ### Phase 3 — Bump version & ghi entry changelog
112
211
 
@@ -134,6 +233,8 @@ Changes :
134
233
  - {change 1}
135
234
  - {change 2}
136
235
 
236
+ 💡 Vừa áp {N} phương án (gồm bản PO tự sửa) → chạy lại /refine-prd {prd-file}
237
+ (delta tự động) để lòi edge case mà các phương án vừa áp có thể tạo ra.
137
238
  ⚠️ BDD có thể đã lỗi thời. Chạy:
138
239
  /review-context {prd-file} ← kiểm tra chất lượng PRD trước
139
240
  → /generate-bdd {prd-file}
@@ -27,6 +27,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
27
27
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
28
28
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
29
29
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
30
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
30
31
  - Đi thẳng tới phần logic riêng của lệnh.
31
32
  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).
32
33
 
@@ -18,6 +18,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
18
18
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
19
19
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
20
20
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
21
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
21
22
  - Đi thẳng tới phần logic riêng của lệnh.
22
23
  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).
23
24
 
@@ -19,6 +19,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
19
19
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
20
20
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
21
21
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
22
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
22
23
  - Đi thẳng tới phần logic riêng của lệnh.
23
24
  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).
24
25
 
@@ -437,10 +438,12 @@ dừng ở mức "đủ" findings, nên mỗi vòng review sau lại lòi ra v
437
438
  fan out song song theo các chiều review, rồi lặp một critic độ-đầy-đủ cho tới khi một
438
439
  vòng không sinh thêm gì mới, *trước khi* ghi file findings.
439
440
 
440
- Lệnh gọi cung cấp hai thứ:
441
+ Lệnh gọi cung cấp hai thứ bắt buộc + hai tuỳ chọn:
441
442
  - **DIMENSIONS** — danh sách các chiều review để fan out
442
443
  (`/refine-prd` → 4 lăng kính; `/review-context` → các P-check hoặc B-check).
443
444
  - **FINDINGS SCHEMA** — dạng YAML mà mỗi finding phải theo (định nghĩa trong lệnh).
445
+ - **GRANULARITY** *(tuỳ chọn, mặc định `auto`)* — `auto`: chọn độ mịn fan-out theo bảng ngưỡng kích thước ở Phase 1 (hành vi cũ). `per-uc`: **LUÔN** fan-out theo từng UC, **bỏ qua ngưỡng** — dùng cho review cần độ đầy đủ cao (`/refine-prd` truyền cái này để lần đầu đã quét sâu). Lệnh không truyền → `auto` → hành vi không đổi.
446
+ - **CHANGED_SCOPE** *(tuỳ chọn)* — danh sách UC/section đã thay đổi (review **delta**). Nếu được truyền, Phase 1 chỉ fan-out trên các phạm vi này + PRD-global; Phase 2 critic vẫn quét **toàn doc** làm lưới an toàn. Không truyền → quét toàn bộ như thường.
444
447
 
445
448
  > **Bỏ qua ở chế độ sub-agent:** Nếu Gate Bước 0 đã set `_agent_mode: true`, toàn bộ
446
449
  > quy trình này bị **bỏ qua** — orchestrator đã chạy sẵn một dimension/UC cho mỗi
@@ -452,8 +455,11 @@ Lệnh gọi cung cấp hai thứ:
452
455
 
453
456
  **Bao nhiêu sub-agent:** *số lượng* agent không phải là đòn bẩy độ đầy đủ — bề rộng được
454
457
  cố định bởi taxonomy DIMENSION (thêm agent vào cùng một dimension chỉ tìm lại cùng vấn đề),
455
- còn *độ sâu* thuộc về vòng lặp critic ở Phase 2. Chọn **độ mịn fan-out**
456
- theo kích thước target, tái dùng ngưỡng của `steps/spawn-agent.md`:
458
+ còn *độ sâu* thuộc về vòng lặp critic ở Phase 2.
459
+
460
+ **Nếu `GRANULARITY = per-uc`:** **bỏ qua bảng ngưỡng dưới đây**, luôn dùng độ mịn **DIMENSION × phạm vi UC** (kể cả PRD nhỏ) — đảm bảo quét sâu, không bỏ sót ngay lần đầu. (Cái giá: nhiều agent hơn cho PRD nhỏ — chấp nhận để lần đầu đầy đủ.)
461
+
462
+ **Nếu `GRANULARITY = auto`** (mặc định): chọn **độ mịn fan-out** theo kích thước target, tái dùng ngưỡng của `steps/spawn-agent.md`:
457
463
 
458
464
  | Kích thước target | Độ mịn | Số agent |
459
465
  |-------------|-------------|-------------|
@@ -476,6 +482,7 @@ UC duy nhất — chính là điều ngăn bỏ sót trên các PRD lớn.
476
482
  agent). Giới hạn mỗi wave ở **`AGENT_CAP = 12`** agent và gom batch các phạm vi UC cho vừa:
477
483
 
478
484
  1. Dựng danh sách phạm vi = `[UC1, UC2, …, UCn, PRD-global]` (độ dài `UCs + 1`).
485
+ - **Nếu `CHANGED_SCOPE` được truyền (review delta):** danh sách phạm vi = `[các UC trong CHANGED_SCOPE] + [PRD-global]` (chỉ các UC đã đổi + global), KHÔNG phải tất cả UC. Số agent tụt theo đó.
479
486
  2. Tính số-phạm-vi-mỗi-bucket: `groups = max(1, floor(AGENT_CAP / dimensions))`.
480
487
  - Nếu `groups ≥ UCs + 1` → không cần batch, chạy một agent cho mỗi `DIMENSION × scope`.
481
488
  - Else chia danh sách phạm vi thành `groups` bucket liền kề kích thước xấp xỉ bằng nhau
@@ -517,10 +524,20 @@ Gom mảng findings của mọi sub-agent vào một danh sách hợp nhất `AL
517
524
  Đây là bước chống đập-chuột-chũi. Lặp cho tới khi **hai vòng liên tiếp thêm 0 finding
518
525
  mới**, hoặc tới cap cứng **3 vòng**, cái nào đến trước:
519
526
 
527
+ > **Lưu ý delta:** kể cả khi `CHANGED_SCOPE` giới hạn Phase 1 vào các UC đã đổi, completeness-critic ở Phase 2 **vẫn đọc TOÀN bộ doc** — đây là lưới an toàn bắt các vấn đề mà một fix ở UC đã đổi có thể làm lộ ra ở chỗ khác.
528
+
520
529
  1. Spawn một sub-agent **completeness-critic** bằng Agent tool. Cho nó:
521
530
  - toàn bộ target file (`{target_file}`),
522
- - danh sách `ALL_FINDINGS` hiện tại (để biết những đã được ghi nhận),
523
- - cùng context gọn đó.
531
+ - danh sách findings đã ghi nhận dưới dạng **slim JSON** chỉ 3 fields cốt lõi
532
+ đủ để critic nhận ra trùng lặp (không cần `quote`, `suggestion`, `auto_fixable`, `severity`):
533
+ ```json
534
+ [
535
+ { "uc_id": "...", "section": "...", "finding": "..." },
536
+ ...
537
+ ]
538
+ ```
539
+ Nếu `ALL_FINDINGS` vượt 60 items, rút gọn `finding` xuống còn 80 ký tự đầu mỗi item.
540
+ - cùng slim context (banned terms, canonical entities, layer order, domains).
524
541
  Prompt nó:
525
542
  ```
526
543
  Here is a document and a list of issues already found. Read the WHOLE document.
@@ -19,6 +19,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
19
19
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
20
20
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
21
21
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
22
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
22
23
  - Đi thẳng tới phần logic riêng của lệnh.
23
24
  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).
24
25
 
@@ -18,6 +18,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
18
18
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
19
19
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
20
20
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
21
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
21
22
  - Đi thẳng tới phần logic riêng của lệnh.
22
23
  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).
23
24
 
@@ -18,6 +18,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
18
18
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
19
19
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
20
20
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
21
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
21
22
  - Đi thẳng tới phần logic riêng của lệnh.
22
23
  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).
23
24
 
@@ -1 +1 @@
1
- 0.14.3
1
+ 0.14.5
@@ -19,6 +19,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
19
19
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
20
20
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
21
21
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
22
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
22
23
  - Đi thẳng tới phần logic riêng của lệnh.
23
24
  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).
24
25
 
@@ -16,6 +16,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
16
16
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
17
17
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
18
18
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
19
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
19
20
  - Đi thẳng tới phần logic riêng của lệnh.
20
21
  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).
21
22
 
@@ -402,6 +403,47 @@ Sau khi hoàn thành tất cả các bước, bạn đã nạp:
402
403
  Tiếp tục sang bước kế tiếp của lệnh đang gọi.
403
404
 
404
405
 
406
+ ---
407
+
408
+ ## Ngôn ngữ nghiệp vụ *(áp khi viết BR / AC / Business Logic / Scope)*
409
+ # Business Language Guard — chặn thuật ngữ kỹ thuật rò vào tài liệu nghiệp vụ
410
+
411
+ 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**.
412
+
413
+ > 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ó.
414
+
415
+ ## Bản đồ xử lý (3 nhóm)
416
+
417
+ **Nhóm 1 — Tương tác/triển khai → DIỄN ĐẠT LẠI sang nghiệp vụ (giữ nguyên nghĩa):**
418
+
419
+ | Kỹ thuật/UI | Cách nói nghiệp vụ |
420
+ |---|---|
421
+ | re-render / render lại / reload / refresh (màn) | "hiển thị lại {tên màn}" |
422
+ | timeout | "quá thời gian chờ" |
423
+ | lỗi mạng / network error | "lỗi kết nối" |
424
+ | UI / giao diện (khi chỉ một màn) | "màn" / "màn hình" |
425
+ | click / tap | "bấm" / "chọn" |
426
+ | popup / modal (nếu chỉ là khái niệm hiển thị) | "hộp thoại" / "thông báo" |
427
+ | disable / enable (nút) | "khoá" / "mở" thao tác |
428
+ | redirect / navigate | "chuyển tới {màn}" |
429
+
430
+ **Nhóm 2 — Visual thuần → CHUYỂN Design Spec (bỏ khỏi PRD, ghi nhận lại):**
431
+ `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."*
432
+
433
+ **Nhóm 3 — Backend/contract thuần → BỎ khỏi PRD (thuộc Tech Docs):**
434
+ `API`, `endpoint`, `token/JWT`, `HTTP status`, tên class/bảng/cột DB, query, payload, header.
435
+ *(Ngoại lệ DUY NHẤT: Appendix "Existing API Contract" khi `API Source: existing` — xem Platform Strategy.)*
436
+
437
+ ## Quy tắc áp dụng
438
+ - Quét toàn bộ text sắp ghi (User Story, AC, BR, Business Logic, Scope, Edge Cases, Assumptions…).
439
+ - 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).
440
+ - Nhóm 2 → gỡ khỏi prose nghiệp vụ + nhắc chuyển Design Spec.
441
+ - Nhóm 3 → gỡ khỏi PRD (trừ ngoại lệ brownfield).
442
+ - 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.
443
+
444
+ **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).
445
+
446
+
405
447
  ---
406
448
 
407
449
  ## Phase 0 — Knowledge Sync *(AI tự điền — bối cảnh hệ thống, KHÔNG phải yêu cầu nghiệp vụ; không cần input PO)*
@@ -412,6 +454,11 @@ AI quét dự án và ghi:
412
454
  - **Phần hệ thống / feature liên quan** — liệt kê phần hệ thống/feature bị ảnh hưởng.
413
455
  - **Rule / Logic có sẵn** — các rule từ PRD có sẵn mà feature này phải tôn trọng.
414
456
  - **Chuẩn hoá thuật ngữ** — map mọi thuật ngữ trong input PO về thuật ngữ chuẩn từ business-dictionary.md.
457
+ - **NEW TERM DETECTION:** nếu một thuật ngữ trong input PO lặp ≥2 lần và KHÔNG có canonical tương ứng trong business-dictionary.md → KHÔNG để trống/bịa. Ghi nó thành một câu hỏi trong **Phase 3 (Clarification Log)** để hỏi PO ngay khi còn trong buổi discovery:
458
+ + Thuật ngữ đó nghĩa gì trong ngữ cảnh hệ thống?
459
+ + English canonical term nên dùng là gì?
460
+ + Có bổ sung vào business-dictionary.md không?
461
+ Sau khi PO chốt → cập nhật business-dictionary.md (nếu đồng ý) + điền vào bảng map. *(Phase 0 chỉ phát hiện; việc hỏi dồn vào Phase 3 để không phá tính chất "không cần input PO" của Phase 0.)*
415
462
 
416
463
  ```
417
464
  | Thuật ngữ trong input PO | Thuật ngữ chuẩn (business-dictionary) |
@@ -451,8 +498,12 @@ Hỏi:
451
498
  ```
452
499
  | Bước | Hành động | Trạng thái/Kết quả nghiệp vụ | Ghi chú |
453
500
  ```
454
- 3. **Exit Point**: Kết quả cuối khi flow hoàn thành là gì?
455
- 4. **Edge Cases**: Các kịch bản thất bại nghiệp vụ ngoài happy path? (input thiếu, điều kiện không thoả, thao tác đồng thời, phụ thuộc không sẵn sàng → kết quả nghiệp vụ kỳ vọng)
501
+ 3. **Màn hình & thành phần chính** *(mức nghiệp vụ — KHÔNG pixel/layout/màu)*: Feature gồm những **màn hình / bước giao diện** chính nào? Mỗi màn có **thành phần & hành động chính** gì (vd: ô nhập, nút, danh sách → bấm ra kết quả gì)? Đây nguồn cho Wireframe của PRD và độ phủ BDD — nếu PO không chắc, AI gợi ý rồi PO xác nhận.
502
+ ```
503
+ | Màn hình | Thành phần chính | Hành động → kết quả nghiệp vụ |
504
+ ```
505
+ 4. **Exit Point**: Kết quả cuối khi flow hoàn thành là gì?
506
+ 5. **Edge Cases**: Các kịch bản thất bại nghiệp vụ ngoài happy path? (input thiếu, điều kiện không thoả, thao tác đồng thời, phụ thuộc không sẵn sàng → kết quả nghiệp vụ kỳ vọng)
456
507
 
457
508
  Xác nhận → ghi `✅ PO xác nhận: Có` → tiếp tục.
458
509
 
@@ -541,6 +592,15 @@ Nếu phát hiện GAP → cảnh báo PO và giải quyết trước khi đánh
541
592
 
542
593
  Ghi `{paths.product_definitions_dir}/{TICKET-ID}-{slug}.md` theo `templates/product-definition.template.md`.
543
594
 
595
+ > **Quy ước `slug`:** `slug` = kebab-case của tên feature (vd "Loyalty Points" → `loyalty-points`),
596
+ > viết thường, chỉ a-z 0-9 và dấu `-`. Đây là định danh feature-package dùng xuyên suốt pipeline —
597
+ > PRD, BDD, tech-docs, design-spec, trace của feature này đều kế thừa **nguyên văn** `slug` này
598
+ > (`/generate-prd` đặt `prd-slug = slug`). Sinh một lần ở đây, các bước sau KHÔNG tái sinh.
599
+ >
600
+ > **Ranh giới tên file:** tên file = `{TICKET-ID}-{slug}.md`. TICKET-ID **được phép chứa `-`**
601
+ > (vd Jira key `LOYAL-29` → `LOYAL-29-loyalty-points.md`). Khi tách lại slug, các bước sau strip
602
+ > **đúng chuỗi TICKET-ID** ở đầu, KHÔNG tách theo dấu `-` đầu tiên.
603
+
544
604
  Điền tất cả section bằng dữ liệu thu thập qua các phase.
545
605
 
546
606
  **Cập nhật Metadata theo tiến độ (cho phép resume):**
@@ -650,8 +710,13 @@ Next : {lệnh gợi ý kèm ví dụ tham số}
650
710
  *(Bỏ dòng `Pipeline` cho các lệnh xuyên suốt liệt kê ở trên.)*
651
711
 
652
712
 
713
+ Ví dụ footer cho lệnh này:
714
+
653
715
  ```
654
- /define-product Hoàn tất ✅
655
- File: {paths.product_definitions_dir}/{TICKET-ID}-{slug}.md
656
- Next: /generate-prd {paths.product_definitions_dir}/{TICKET-ID}-{slug}.md
716
+ ---
717
+ Status : ✅ Complete
718
+ Output Artifacts:
719
+ created {paths.product_definitions_dir}/{TICKET-ID}-{slug}.md (product definition, Phase 1-7)
720
+ Pipeline : [Discovery ◀ bạn ở đây] → PRD → Design Spec → BDD → Tech Design → Code → Dev Self-Check → QC → Trace Audit
721
+ Next : /generate-prd {paths.product_definitions_dir}/{TICKET-ID}-{slug}.md
657
722
  ```
@@ -22,6 +22,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
22
22
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
23
23
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
24
24
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
25
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
25
26
  - Đi thẳng tới phần logic riêng của lệnh.
26
27
  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).
27
28
 
@@ -22,6 +22,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
22
22
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
23
23
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
24
24
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
25
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
25
26
  - Đi thẳng tới phần logic riêng của lệnh.
26
27
  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).
27
28
 
@@ -18,6 +18,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
18
18
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
19
19
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
20
20
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
21
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
21
22
  - Đi thẳng tới phần logic riêng của lệnh.
22
23
  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).
23
24
 
@@ -16,6 +16,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
16
16
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
17
17
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
18
18
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
19
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
19
20
  - Đi thẳng tới phần logic riêng của lệnh.
20
21
  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).
21
22
 
@@ -16,6 +16,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
16
16
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
17
17
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
18
18
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
19
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
19
20
  - Đi thẳng tới phần logic riêng của lệnh.
20
21
  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).
21
22
 
@@ -566,17 +567,21 @@ Từ vựng step của System BDD (luôn dùng — bất kể từ vựng FE/App
566
567
 
567
568
  *Bỏ qua section này nếu đang chạy spec repo mode.*
568
569
 
569
- Đọc bảng Metadata của PRD tìm row `| **Service** |` `| **Module** |`.
570
+ Routing service **domain-keyed** và **context-loader (Bước 1.5) đã phân giải sẵn** từ `@trace.domain`/Domain của PRD KHÔNG re-resolve đây, chỉ dùng lại các biến đã set:
571
+ - `active_service` = `services.{domain}.path` (path submodule, vd `user-service/`) — hoặc `"unresolved"` nếu domain không khớp entry nào, hoặc bỏ trống ở single-service.
572
+ - `active_module` = module của service (`services.{domain}.module`, đã override `tech_stack.module` ở Bước 1.5) — dùng cho từ vựng bên dưới.
570
573
 
571
- | Điều kiện | Hành động |
574
+ Chỉ cần kiểm tra trạng thái đã phân giải:
575
+
576
+ | Trạng thái (từ context-loader) | Hành động |
572
577
  |---|---|
573
- | PRD có row `Service` giá trị không phải "default" | Dùng làm `active_service` + `active_module`. Nạp catalog cho module đó. |
574
- | PRD khôngrow `Service` `services` được định nghĩa trong project-context.yaml | Hỏi: "BDD này dành cho service nào?" (liệt service, chờ chọn) |
575
- | Dự án single-service (không có mảng `services`) | `active_service = "default"`, `active_module = tech_stack.module` |
578
+ | `active_service` đã phân giải thành path service | Tiếp tục với `active_module` đã set. |
579
+ | `active_service = "unresolved"` (section `services` nhưng domain PRD không khớp entry nào) | **DỪNG**, báo: "Domain `{domain}` của PRD không khớp service nào trong `services:` của project-context.yaml bổ sung mapping rồi chạy lại." (Không đoán/hỏi tay — domain là khoá định danh, lệch là lỗi cấu hình cần sửa ở SoT.) |
580
+ | Single-service (không có section `services`) | `active_module = tech_stack.module` (đã set ở Bước 6.5). Tiếp tục. |
581
+
582
+ **Output path (umbrella mode):** `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC{N}-{slug}.feature`
576
583
 
577
- **Output path (umbrella mode):**
578
- - `active_service = "default"` → `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC{N}-{slug}.feature`
579
- - `active_service ≠ "default"` → `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_service}/{TICKET-ID}-UC{N}-{slug}.feature`
584
+ *(Không thêm subfolder theo service: feature-package đã domain-scoped sẵn ở `{domain}/`, mà service route 1-1 theo domain — nên thêm subfolder service sẽ chỉ lặp lại domain. `active_service` chỉ dùng cho `service_root`/từ vựng, KHÔNG vào path spec.)*
580
585
 
581
586
  **Từ vựng theo platform** — điều chỉnh cách viết step BDD theo `active_module`:
582
587
 
@@ -626,7 +631,7 @@ Trước khi sinh, kiểm tra các file `.feature` có sẵn cho PRD này:
626
631
 
627
632
  1. Phân giải search path theo mode:
628
633
  - **Spec repo mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC*.feature`
629
- - **Umbrella mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC*.feature` (hoặc với `{active_service}/` nếu multi-service)
634
+ - **Umbrella mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC*.feature`
630
635
  2. Đọc `| **Version** |` hiện tại của PRD từ metadata (vd: `1.2`).
631
636
 
632
637
  **Nếu không có file feature nào** → gen mới, tiếp tục bình thường. Dùng version PRD làm `@trace.prd_version`.
@@ -731,8 +736,7 @@ CHECKPOINT: "Outline này đúng chưa? Bạn muốn thêm hay bớt SC nào kh
731
736
 
732
737
  **Output path theo mode:**
733
738
  - **Spec repo mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC{N}-{slug}.feature`
734
- - **Umbrella mode (single-service)**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC{N}-{slug}.feature`
735
- - **Umbrella mode (multi-service)**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_service}/{TICKET-ID}-UC{N}-{slug}.feature`
739
+ - **Umbrella mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC{N}-{slug}.feature` *(service route 1-1 theo domain → không thêm subfolder service)*
736
740
 
737
741
  Với mỗi UC, ghi vào path đã phân giải ở trên. Dùng từ vựng cho active platform (từ Platform Selection hoặc Service Detection).
738
742
 
@@ -16,6 +16,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
16
16
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
17
17
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
18
18
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
19
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
19
20
  - Đi thẳng tới phần logic riêng của lệnh.
20
21
  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).
21
22
 
@@ -16,6 +16,7 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
16
16
  - Đặt loaded context = `payload.context` (KHÔNG chạy context-loader.md)
17
17
  - Đặt phạm vi UC = `payload.uc_id` (chỉ xử lý UC này)
18
18
  - Đặt line range = `payload.uc_section` (chỉ đọc đúng section đó của PRD)
19
+ - Đặt dimension = `payload.dimension` nếu có (lệnh review per-UC: chỉ review đúng lăng kính này)
19
20
  - Đi thẳng tới phần logic riêng của lệnh.
20
21
  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).
21
22