@educa-corp/sdd-framework 0.9.5 → 0.9.7

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 (113) hide show
  1. package/bin/build.js +11 -1
  2. package/bin/lint-trace.js +397 -28
  3. package/bin/self-check.js +623 -16
  4. package/bin/trace-schema.json +3187 -1981
  5. package/core/FRAMEWORK_VERSION +1 -1
  6. package/core/commands/amend-prd.md +7 -1
  7. package/core/commands/debug.md +8 -2
  8. package/core/commands/define-product.md +38 -1
  9. package/core/commands/dev-gen-test.md +70 -2
  10. package/core/commands/dev-run-test.md +8 -2
  11. package/core/commands/dev-smoke-test.md +7 -1
  12. package/core/commands/extend-prd.md +7 -1
  13. package/core/commands/fix-bug.md +11 -5
  14. package/core/commands/generate-architecture.md +9 -1
  15. package/core/commands/generate-bdd.md +45 -5
  16. package/core/commands/generate-code.md +44 -5
  17. package/core/commands/generate-design-spec.md +7 -1
  18. package/core/commands/generate-prd.md +9 -1
  19. package/core/commands/generate-spec-manifest.md +7 -1
  20. package/core/commands/generate-tech-docs.md +44 -4
  21. package/core/commands/learn.md +7 -1
  22. package/core/commands/map-testids.md +96 -13
  23. package/core/commands/propose-scenario.md +7 -1
  24. package/core/commands/qc-analyze.md +516 -426
  25. package/core/commands/qc-automation-assess.md +356 -0
  26. package/core/commands/qc-design-script.md +400 -0
  27. package/core/commands/qc-design-test.md +482 -248
  28. package/core/commands/qc-plan.md +141 -94
  29. package/core/commands/qc-report.md +9 -3
  30. package/core/commands/{qc-review.md → qc-review-script.md} +172 -132
  31. package/core/commands/qc-review-testcase.md +409 -0
  32. package/core/commands/qc-run-manualtest.md +401 -0
  33. package/core/commands/{qc-run-test.md → qc-run-script.md} +200 -232
  34. package/core/commands/refine-prd.md +7 -1
  35. package/core/commands/report-bug.md +9 -3
  36. package/core/commands/review-code.md +9 -3
  37. package/core/commands/review-context.md +11 -3
  38. package/core/commands/review-tech-docs.md +11 -3
  39. package/core/commands/setup-ai-first.md +7 -1
  40. package/core/commands/validate-traces.md +27 -6
  41. package/core/modules/qc-playwright/stack-profile.yaml +1 -1
  42. package/core/rules/workflow.md +42 -2
  43. package/core/skills/qc/_shared/self-review-principles.md +2 -2
  44. package/core/skills/qc/qa-analyst/DOC_GAP.template.md +10 -2
  45. package/core/skills/qc/qa-analyst/spec-issue-reporter.md +1 -1
  46. package/core/skills/qc/qa-automation-assess/matrix.md +120 -0
  47. package/core/skills/qc/qa-designer/e2e/journey.md +1 -1
  48. package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +1 -1
  49. package/core/skills/qc/qa-designer/functional/api.md +1 -1
  50. package/core/skills/qc/qa-designer/functional/gui-feature.md +1 -1
  51. package/core/skills/qc/qa-designer/functional/gui-screen.md +1 -1
  52. package/core/skills/qc/qa-designer/integration/api.md +1 -1
  53. package/core/skills/qc/qa-designer/integration/db.md +1 -1
  54. package/core/skills/qc/qa-designer/integration/gui.md +1 -1
  55. package/core/skills/qc/qa-designer/integration/kafka.md +1 -1
  56. package/core/skills/qc/qa-designer/non-functional.md +1 -1
  57. package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +33 -5
  58. package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +34 -5
  59. package/core/skills/qc/qa-planner/test-plan.md +7 -0
  60. package/core/skills/qc/qa-reviewer/script/e2e.md +1 -1
  61. package/core/skills/qc/qa-reviewer/script/exploratory.md +1 -1
  62. package/core/skills/qc/qa-reviewer/script/functional.md +1 -1
  63. package/core/skills/qc/qa-reviewer/script/integration.md +1 -1
  64. package/core/skills/qc/qa-reviewer/script/non-functional.md +1 -1
  65. package/core/skills/qc/qa-reviewer/shared/review-file-template.md +3 -3
  66. package/core/skills/qc/qa-reviewer/test-case/e2e.md +1 -1
  67. package/core/skills/qc/qa-reviewer/test-case/functional.md +1 -1
  68. package/core/skills/qc/qa-reviewer/test-case/integration.md +1 -1
  69. package/core/skills/qc/qa-reviewer/test-case/non-functional.md +1 -1
  70. package/core/skills/qc/qa-runner/e2e.md +2 -2
  71. package/core/skills/qc/qa-runner/functional/gui-feature.md +4 -4
  72. package/core/skills/qc/qa-runner/functional/gui-screen.md +4 -4
  73. package/core/skills/qc/qa-runner/integration.md +1 -1
  74. package/core/skills/qc/qa-runner/non-functional.md +1 -1
  75. package/core/steps/context-loader.md +1 -1
  76. package/core/steps/gate.md +7 -1
  77. package/core/steps/qc-scope.md +67 -11
  78. package/core/steps/qc-stamp.md +142 -0
  79. package/core/steps/report-footer.md +19 -10
  80. package/core/templates/tech-design.template.md +3 -3
  81. package/docs/01-getting-started/quickstart.md +4 -3
  82. package/docs/02-concepts/architecture.md +14 -0
  83. package/docs/02-concepts/glossary.md +8 -0
  84. package/docs/02-concepts/overview.md +3 -2
  85. package/docs/02-concepts/pipeline-steps/04-bdd.md +1 -1
  86. package/docs/02-concepts/pipeline-steps/05-tech-docs.md +21 -5
  87. package/docs/02-concepts/pipeline-steps/06-code.md +12 -2
  88. package/docs/02-concepts/pipeline-steps/07-dev-selftest.md +1 -1
  89. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +65 -16
  90. package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +3 -3
  91. package/docs/02-concepts/pipeline-steps/README.md +4 -3
  92. package/docs/02-concepts/traceability.md +2 -2
  93. package/docs/03-guides/architect.md +2 -2
  94. package/docs/03-guides/developer.md +6 -3
  95. package/docs/03-guides/tester-qa.md +23 -10
  96. package/docs/04-reference/commands.md +9 -4
  97. package/docs/04-reference/trace-schema.md +5 -5
  98. package/docs/explain/07-generate-tech-docs.md +5 -3
  99. package/docs/explain/08-review-tech-docs.md +15 -3
  100. package/docs/explain/09-generate-code.md +30 -4
  101. package/docs/explain/10-review-code.md +1 -1
  102. package/docs/explain/11-map-testids.md +72 -70
  103. package/docs/explain/12-dev-gen-test.md +1 -1
  104. package/docs/explain/15-qc-analyze.md +14 -2
  105. package/docs/explain/16-qc-plan.md +5 -1
  106. package/docs/explain/17-qc-design-test.md +30 -7
  107. package/docs/explain/18-qc-review.md +43 -17
  108. package/docs/explain/19-qc-run-test.md +38 -12
  109. package/docs/explain/20-qc-report.md +8 -5
  110. package/docs/explain/23-fix-bug.md +2 -2
  111. package/docs/explain/README.md +6 -3
  112. package/docs/plans/qc-surgery/01-checklist.md +70 -17
  113. package/package.json +1 -1
@@ -5,7 +5,12 @@ ported_from: ui-automation-testing
5
5
  upstream_path: skills/qa-tc-designer/shared/tc-metadata-format.md
6
6
  upstream_sha: a31d66a7a8dab19cf821c9102a88282b09e16cb9
7
7
  ---
8
- # TC Metadata Format (Chuẩn chung)
8
+ # TC Metadata Format
9
+
10
+ > **`Automatable` KHÔNG phải một field của `.Test.md`.** Quyết định *"TC này máy chạy được hay
11
+ > phải chạy tay"* sống ở **đúng một chỗ**: `{qc_artifact_dir}AUTOMATION_ASSESSMENT.md`, do
12
+ > `/qc-automation-assess` ghi. Đừng chép giá trị đó vào đây — hai nơi ghi cùng một quyết định
13
+ > thì một nơi sẽ lệch, và lúc đó không ai biết nơi nào đúng. (Chuẩn chung)
9
14
 
10
15
  ## ⚠️ Nguyên tắc format file TC (BẮT BUỘC — QC yêu cầu)
11
16
 
@@ -57,9 +62,14 @@ Mỗi trường 1 dòng, không bảng, không emoji dư:
57
62
  - **Author:** AI
58
63
  - **Tags:** <lane>, <loại: smoke|sanity|regression>, <feature-tag>
59
64
  - **Trace:** BR-xx (ID gốc trong PRD/BDD ở `{paths.specs_dir}`)
65
+ - **@trace.verifies:** {UC-ID}-SC{N}
60
66
  - **🚫 Block:** [GAP-UC{N}-{nnn}](../DOC_GAP.md) — <lý do> *(chỉ khi có)*
61
67
  ```
62
68
 
69
+ > **`@trace.verifies` là trường BẮT BUỘC, không phải tuỳ chọn** — §Trace dưới đây gọi nó là
70
+ > **join key**: thiếu nó thì kết quả chạy **không vào được sổ trace**. Nó từng vắng mặt ở hai khối
71
+ > mẫu này trong khi §Trace vẫn đòi nó — nên ai copy khối mẫu là bỏ sót đúng trường quan trọng nhất.
72
+
63
73
  ## Quy tắc Trace & Block
64
74
 
65
75
  - **Trace:** ghi `BR-xx` lấy từ ID trong `{paths.specs_dir}`; không có BR → `⚠️ Chưa có Business Rule`.
@@ -76,6 +86,7 @@ Mỗi trường 1 dòng, không bảng, không emoji dư:
76
86
  - **Author:** AI
77
87
  - **Tags:** ...
78
88
  - **Trace:** BR-xx
89
+ - **@trace.verifies:** {UC-ID}-SC{N}
79
90
  - **🚫 Block:** (nếu có)
80
91
 
81
92
  #### Preconditions
@@ -199,7 +210,7 @@ Mọi thứ trên là chuẩn của đội QC. Bốn thứ dưới đây là **c
199
210
  **Câu hỏi phân file:** *"TC này verify được mà **không cần UI** không?"*
200
211
  → **có** = file API · **không** = file giao diện. *(Trùng Bước 2 của `skill-decision-tree.md`.)*
201
212
 
202
- ⚠️ **Đuôi file là `.Test.md`, không phải `.md`.** `/qc-run-test` và `/qc-review` tìm `*.Test.md`;
213
+ ⚠️ **Đuôi file là `.Test.md`, không phải `.md`.** `/qc-design-script` và `/qc-review-testcase` tìm `*.Test.md`;
203
214
  ghi ra file thiếu phần `.Test` là ghi ra thứ **không trạm nào tìm thấy**, và không có gì báo lỗi.
204
215
 
205
216
  Đánh số `TC_<FEATURE>_NNN` **liên tục toàn file**, không đánh lại theo từng nhóm.
@@ -209,7 +220,7 @@ ghi ra file thiếu phần `.Test` là ghi ra thứ **không trạm nào tìm th
209
220
  | Trường | Dạng | Vì sao cần |
210
221
  |---|---|---|
211
222
  | `**Trace:**` | `[BR-xx](../REQUIREMENT_ANALYSIS.md#3-business-rules)` — không có BR → `⚠️ Chưa có Business Rule` | truy về luật nghiệp vụ |
212
- | `**@trace.verifies:**` | `{UC-ID}-SC{N}` (lấy từ `@trace.scenario` của file `.feature`) | **join key** để `/qc-run-test` ghi `qc_status` theo từng kịch bản vào sổ trace |
223
+ | `**@trace.verifies:**` | `{UC-ID}-SC{N}` (lấy từ `@trace.scenario` của file `.feature`) | **join key** để `/qc-run-script` ghi `qc_status` theo từng kịch bản vào sổ trace |
213
224
 
214
225
  Một `SC` map được nhiều TC. **Thiếu `@trace.verifies` thì kết quả chạy không vào được sổ** — TC
215
226
  vẫn chạy, vẫn pass/fail, nhưng không ai biết nó phủ kịch bản nào.
@@ -226,6 +237,24 @@ sách**, không bảng (§Nguyên tắc format file đầu tài liệu này).
226
237
  `DOC_GAP.md` nằm ở **thư mục cha** của `test-cases/`, nên liên kết đi lên một cấp. Mã gap mang
227
238
  UC (`GAP-UC1-001`) vì một file gap phủ cả PRD.
228
239
 
240
+ ## Khối `Nguồn & phiên bản` *(metadata đầu file)*
241
+
242
+ Ghi ngay dưới dòng `Test-ID attribute`:
243
+
244
+ ```
245
+ Nguồn & phiên bản: BDD {UC-ID} `<vX.Y>` · tech-doc `<rev | —>`
246
+ ```
247
+
248
+ Lấy `<vX.Y>` từ `| **Version** |` ở header `.feature` của **chính UC này**, và `<rev>` từ header
249
+ tech-doc gộp. `/qc-review-testcase` và `/qc-design-script` **so** khối này với version hiện tại để biết bộ TC còn
250
+ khớp spec không (`steps/qc-stamp.md` · `bin/trace-schema.json` → `qc_artifact_stamp`).
251
+
252
+ **Vì sao cần, khi sổ trace đã có `qc_status`.** `/generate-bdd` hạ `qc_status → not_run` khi spec đổi
253
+ — đó là *"**kết quả chạy** hết hiệu lực"*, và việc phải làm là **chạy lại**. Khối này trả lời câu
254
+ khác: *"**bộ TC** còn khớp không?"*, và việc phải làm là **viết lại**. Thiếu nó thì người ta thấy
255
+ `not_run` rồi chạy lại một bộ TC lỗi thời — ra `pass`, và `pass` đó **hợp lệ theo mọi phép kiểm hiện
256
+ có**.
257
+
229
258
  ## Dòng `Test-ID attribute`
230
259
 
231
260
  Ghi một dòng ở phần metadata **đầu file**:
@@ -235,8 +264,8 @@ Test-ID attribute: {attr}
235
264
  ```
236
265
 
237
266
  Đọc `@trace.testid_attr` từ header tech-doc gộp (do `/map-testids` ghi). Bảng §4.5.6 chỉ cho
238
- **giá trị** test-id; đây là **tên thuộc tính** chứa chúng. `/qc-run-test` cần nó để cấu hình
239
- locator, `/qc-review` cần nó để biết selector trong script có đúng hợp đồng không.
267
+ **giá trị** test-id; đây là **tên thuộc tính** chứa chúng. `/qc-design-script` cần nó để cấu hình
268
+ locator, `/qc-review-script` cần nó để biết selector trong script có đúng hợp đồng không.
240
269
 
241
270
  Thiếu field trong tech-doc → ghi `Test-ID attribute: — (thiếu @trace.testid_attr, chạy /map-testids)`.
242
271
  **Đừng bỏ trống và đừng tự đoán** — đoán sai thì mọi locator trượt 100%, và trượt vì lý do
@@ -72,6 +72,13 @@ Tổng hợp **output của qa-analyst** thành **Test Plan** cho một feature
72
72
  | Người lập | qa-planner |
73
73
  | Ngày / Phiên bản | … |
74
74
  | Nguồn | REQUIREMENT_ANALYSIS · DOC_GAP |
75
+ | **Nguồn & phiên bản** | PRD `<vX.Y>` · tech-doc `<rev \| —>` · design-spec `<vX.Y \| —>` |
76
+ | **BDD theo UC** | `<UC-ID>` `<vX.Y>` · `<UC-ID>` `<vX.Y>` … |
77
+
78
+ > **Hai hàng cuối: CHÉP LẠI từ khối stamp của `DOC_GAP.md`, KHÔNG tự đi lấy từ spec.**
79
+ > Trạm này không đọc spec trực tiếp — đầu vào của nó là output trạm 1. Tự đi lấy là tạo **hai
80
+ > nguồn cho một số**, rồi chúng lệch nhau và không ai biết bên nào đúng.
81
+ > `/qc-design-test` so hai hàng này với version hiện tại (`steps/qc-stamp.md`).
75
82
 
76
83
  ## 1. Mục tiêu
77
84
  Mục tiêu test của feature (1–3 câu).
@@ -92,4 +92,4 @@ Severity: 🔴 fix ngay (missing cleanup, dữ liệu không verify cross-module
92
92
  (cột `Tầng` phân biệt vai soát-code với vai soát-kịch-bản; **không ghi đè** hàng của vai kia).
93
93
  Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
94
94
 
95
- **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-run-test`.
95
+ **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-design-script`.
@@ -47,7 +47,7 @@ Review session note sau khi test, coaching QC cải thiện kỹ năng.
47
47
  (cột `Tầng` phân biệt vai soát-code với vai soát-kịch-bản; **không ghi đè** hàng của vai kia).
48
48
  Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
49
49
 
50
- **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-run-test`.
50
+ **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-design-script`.
51
51
  Mỗi tiêu chí: ✅/⚠️/❌ + feedback cụ thể
52
52
  Top 3 improvement suggestions (coaching tone)
53
53
  Đề xuất charter tiếp theo nếu chưa đủ coverage
@@ -106,4 +106,4 @@ Severity: 🔴 fix ngay (sai logic, POM breach, silent fail) · 🟠 quan trọn
106
106
  (cột `Tầng` phân biệt vai soát-code với vai soát-kịch-bản; **không ghi đè** hàng của vai kia).
107
107
  Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
108
108
 
109
- **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-run-test`.
109
+ **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-design-script`.
@@ -96,4 +96,4 @@ Severity: 🔴 fix ngay (mock thay real call, missing DB verify, no cleanup) ·
96
96
  (cột `Tầng` phân biệt vai soát-code với vai soát-kịch-bản; **không ghi đè** hàng của vai kia).
97
97
  Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
98
98
 
99
- **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-run-test`.
99
+ **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-design-script`.
@@ -131,4 +131,4 @@ Severity: 🔴 fix ngay (assertion không có ngưỡng, gọi production endpoi
131
131
  (cột `Tầng` phân biệt vai soát-code với vai soát-kịch-bản; **không ghi đè** hàng của vai kia).
132
132
  Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
133
133
 
134
- **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-run-test`.
134
+ **KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-design-script`.
@@ -31,7 +31,7 @@ upstream_sha: bd596393ecc016cbea106835681a4979c0a9ca0e
31
31
  giữa tài-liệu-nền-cũ và PRD đã duyệt là **lệch đồng bộ, KHÔNG chặn** — không phải mâu thuẫn
32
32
  chặn. *(Khung "gap thật = QA KHÔNG tự quyết được" — xem `steps/gap-verify.md`.)*
33
33
  - **KHÔNG tự sửa** kịch bản hay code. Chỉ nhận xét, chấm điểm, và nêu cụ thể sửa gì. Người sửa là
34
- trạm 3 (`/qc-design-test`) hoặc trạm 5 (`/qc-run-test`).
34
+ trạm 3 (`/qc-design-test`) hoặc trạm 5 (`/qc-run-script`).
35
35
 
36
36
  ## Kiểm tra cấu trúc TC (bắt buộc mỗi vòng)
37
37
 
@@ -126,7 +126,7 @@ soát:
126
126
  ```
127
127
 
128
128
  ⚠️ **Tên file review KHÔNG có đuôi `.Test.md`.** Đuôi đó là của file test case; gắn vào file
129
- review sẽ làm `/qc-run-test` nhặt nó lên như một file test case rồi cố sinh script từ một bảng
129
+ review sẽ làm `/qc-design-script` nhặt nó lên như một file test case rồi cố sinh script từ một bảng
130
130
  điểm.
131
131
 
132
132
  - **Chưa tồn tại** → `Write` toàn bộ khuôn bên dưới, điền hàng của tầng vừa soát, các tầng khác
@@ -147,7 +147,7 @@ review sẽ làm `/qc-run-test` nhặt nó lên như một file test case rồi
147
147
  ```markdown
148
148
  # Review Report — <FEATURE>
149
149
 
150
- > Sinh bởi /qc-review. Cập nhật sau mỗi vòng soát. Bảng Tổng quan tích luỹ theo vòng.
150
+ > Sinh bởi /qc-review-testcase hoặc /qc-review-script (mỗi vai một file). Cập nhật sau mỗi vòng soát. Bảng Tổng quan tích luỹ theo vòng.
151
151
 
152
152
  ## Tổng quan
153
153
 
@@ -12,7 +12,7 @@ Review bộ TC end-to-end và đánh giá chất lượng.
12
12
 
13
13
  ## Khi nào trigger
14
14
  - "review TC E2E cho [Feature]" / "check coverage E2E"
15
- - Sau khi qa-designer/e2e/journey xong, trước khi /qc-run-test
15
+ - Sau khi qa-designer/e2e/journey xong, trước khi /qc-design-script
16
16
 
17
17
  ## Khi KHÔNG trigger
18
18
  - Review TC functional 1 màn → `test-case/functional`
@@ -12,7 +12,7 @@ Review bộ functional TC và đánh giá chất lượng.
12
12
 
13
13
  ## Khi nào trigger
14
14
  - "review TC cho [Feature]" / "check coverage"
15
- - Sau khi qa-designer xong, trước khi PO approve hoặc trước khi /qc-run-test
15
+ - Sau khi qa-designer xong, trước khi PO approve hoặc trước khi /qc-design-script
16
16
 
17
17
  ## Khi KHÔNG trigger
18
18
  - Review Python script → dùng qa-reviewer
@@ -12,7 +12,7 @@ Review bộ TC tích hợp (GUI↔Backend, API, DB) và đánh giá chất lư
12
12
 
13
13
  ## Khi nào trigger
14
14
  - "review TC integration cho [Feature]" / "check TC tích hợp"
15
- - Sau khi qa-designer/integration/* xong, trước khi /qc-run-test
15
+ - Sau khi qa-designer/integration/* xong, trước khi /qc-design-script
16
16
 
17
17
  ## Khi KHÔNG trigger
18
18
  - Review TC functional 1 màn/endpoint → `test-case/functional`
@@ -12,7 +12,7 @@ Review bộ TC phi chức năng (performance, security, accessibility, compatibi
12
12
 
13
13
  ## Khi nào trigger
14
14
  - "review TC non-functional cho [Feature]" / "check TC hiệu năng/bảo mật/accessibility"
15
- - Sau khi qa-designer/non-functional xong, trước khi /qc-run-test
15
+ - Sau khi qa-designer/non-functional xong, trước khi /qc-design-script
16
16
 
17
17
  ## Khi KHÔNG trigger
18
18
  - Review TC chức năng → `test-case/functional`
@@ -30,7 +30,7 @@ Journey còn phụ thuộc gap → tạo test `@pytest.mark.skip(reason="GAP-UC{
30
30
 
31
31
  ## Phase 3 — Verify
32
32
  `py_compile` + `pytest --collect-only -q` · chạy (môi trường staging + CRM) · cập nhật Status TC.
33
- **Phân loại FAIL — 3 nhãn, luật ở `/qc-run-test` §Chạy lại trước khi kết luận** (chạy lại ×2 trước, rồi người xác nhận; **không chép lại luật ở đây**). Đặc thù E2E: journey fail vì 1 bước feature chưa wire = `product-gap` (giữ FAIL/skip + bằng chứng), không phải lỗi script; sai selector/state → `script-bug`. Journey dài qua nhiều bước **dễ ra `flaky` hơn test đơn lẻ** — một bước chậm bất thường là đủ; nên đừng vội gọi `product-gap` khi chưa chạy lại.
33
+ **Phân loại FAIL — 3 nhãn, luật ở `/qc-run-script` §Chạy lại trước khi kết luận** (chạy lại ×2 trước, rồi người xác nhận; **không chép lại luật ở đây**). Đặc thù E2E: journey fail vì 1 bước feature chưa wire = `product-gap` (giữ FAIL/skip + bằng chứng), không phải lỗi script; sai selector/state → `script-bug`. Journey dài qua nhiều bước **dễ ra `flaky` hơn test đơn lẻ** — một bước chậm bất thường là đủ; nên đừng vội gọi `product-gap` khi chưa chạy lại.
34
34
 
35
35
  ## Output
36
36
  Script `tests/<project>/e2e/test_<feature>.py` + Page Object/client tái dùng. Bàn giao `qa-reviewer`.
@@ -46,4 +46,4 @@ Report = **Playwright Trace viewer + pytest-html** (KHÔNG Allure, KHÔNG dashbo
46
46
  - HTML report: `reports/<feature>/report.html` (self-contained, mở trực tiếp).
47
47
  - Trace từng test (debug step-by-step): `python3 -m playwright show-trace test-results/<nodeid>/trace.zip`.
48
48
  - Tóm tắt: **TOTAL / PASS / FAIL / SKIP** + duration.
49
- 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-test` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
49
+ 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-script` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
@@ -22,9 +22,9 @@ Skill **tự chứa**: convert `.Test.md` feature span ≥2 màn → Python pyte
22
22
 
23
23
  ## Phase 1 — Clarify
24
24
  Đọc `.Test.md` · liệt kê các màn/PO cần · state truyền giữa màn · fixture dựng tiền điều kiện (data qua nhiều bước).
25
- **Locator: đọc hợp đồng TRƯỚC, dò DOM là bước cuối.** Thứ tự bắt buộc (luật đầy đủ + lý do ở `/qc-run-test` §Role & stack — **không chép lại ở đây**):
25
+ **Locator: đọc hợp đồng TRƯỚC, dò DOM là bước cuối.** Thứ tự bắt buộc (luật đầy đủ + lý do ở `/qc-design-script` §Role & stack — **không chép lại ở đây**):
26
26
 
27
- 1. **Test-id contract** — bảng *Test Selectors* §4.5.6 của tech-doc gộp, lọc theo cột "Phục vụ SC" khớp SC của UC này. TÊN thuộc tính đọc từ `@trace.testid_attr` ở header tech-doc (đừng suy từ platform). Feature đa màn: một UC chạm nhiều màn nhưng **vẫn một bảng §4.5.6** cho cả platform — lọc theo SC, không theo màn.
27
+ 1. **Test-id contract** — bảng *Test Selectors* §4.5.6 của tech-doc gộp, lọc theo cột "Serves SC" khớp SC của UC này. TÊN thuộc tính đọc từ `@trace.testid_attr` ở header tech-doc (đừng suy từ platform). Feature đa màn: một UC chạm nhiều màn nhưng **vẫn một bảng §4.5.6** cho cả platform — lọc theo SC, không theo màn.
28
28
  2. **Role + accessible name** — cho element có action mà §4.5.6 chưa phủ.
29
29
  3. **Dò DOM** — CHỈ khi 1 và 2 đều không định vị được. Dump class/`aria-label`/role, rồi nhìn kết quả:
30
30
  - **3a. Element ĐÃ mang test-id trong code** → **DỪNG, đừng tự dùng id nhặt được.** Đây là ca *code đi trước hợp đồng*: chạy `/map-testids {UC-ID}` để đưa id đó vào §4.5.6 (nhánh `existing` — reverse-document), rồi quay lại bậc 1.
@@ -38,7 +38,7 @@ Phủ TC điều hướng forward/back/giữ-reset state. Data từ `test_data/`
38
38
  ## Phase 3 — Verify
39
39
  `py_compile` + `pytest --collect-only -q` (**số collect = tổng TC**; thiếu → sinh nốt) · chạy · cập nhật Status TC (verify KHÔNG còn Draft) · in mapping.
40
40
  **Gom nhóm role/account** tự áp qua `utils/test_ordering.py` (root conftest); fixture auth mới → `register_auth_fixtures([...])`. ⚠️ Run dài bị **WSL suspend** có thể gây flaky login/timeout → re-run TC đó + merge report.
41
- **Phân loại FAIL — 3 nhãn, luật ở `/qc-run-test` §Chạy lại trước khi kết luận** (chạy lại ×2 trước, rồi người xác nhận; **không chép lại ở đây**). Đặc thù đa màn: sai selector/logic → `script-bug`, sửa & chạy lại; feature chưa wire/defect **đỏ nhất quán** → `product-gap`, giữ FAIL + ghi bằng chứng vào khối "Kết quả thực thi" đầu `.Test.md`, không fake-pass. **State truyền giữa màn là nguồn `flaky` phổ biến** — điều hướng nhanh hơn/chậm hơn một nhịp là đủ đổi kết quả; ghi nghi vấn đó vào phần nguyên nhân.
41
+ **Phân loại FAIL — 3 nhãn, luật ở `/qc-run-script` §Chạy lại trước khi kết luận** (chạy lại ×2 trước, rồi người xác nhận; **không chép lại ở đây**). Đặc thù đa màn: sai selector/logic → `script-bug`, sửa & chạy lại; feature chưa wire/defect **đỏ nhất quán** → `product-gap`, giữ FAIL + ghi bằng chứng vào khối "Kết quả thực thi" đầu `.Test.md`, không fake-pass. **State truyền giữa màn là nguồn `flaky` phổ biến** — điều hướng nhanh hơn/chậm hơn một nhịp là đủ đổi kết quả; ghi nghi vấn đó vào phần nguyên nhân.
42
42
 
43
43
  ## Output
44
44
  Script + nhiều Page Object (mỗi màn) trong `pages/<project>/...`. Bàn giao `qa-reviewer` (script).
@@ -54,4 +54,4 @@ Report = **Playwright Trace viewer + pytest-html** (KHÔNG Allure, KHÔNG dashbo
54
54
  - HTML report: `reports/<feature>/report.html` (self-contained, mở trực tiếp).
55
55
  - Trace từng test (debug step-by-step): `python3 -m playwright show-trace test-results/<nodeid>/trace.zip`.
56
56
  - Tóm tắt: **TOTAL / PASS / FAIL / SKIP** + duration.
57
- 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-test` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
57
+ 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-script` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
@@ -23,9 +23,9 @@ Skill **tự chứa**: convert `.Test.md` (1 màn) → Python pytest + Playwrigh
23
23
 
24
24
  ## Phase 1 — Clarify
25
25
  Đọc `.Test.md` (confirm Reviewed) · platform (web Playwright/mobile) · Page Object đã có chưa → tạo nếu cần · fixture setup data?
26
- **Locator: đọc hợp đồng TRƯỚC, dò DOM là bước cuối.** Thứ tự bắt buộc (luật đầy đủ + lý do ở `/qc-run-test` §Role & stack — **không chép lại ở đây**):
26
+ **Locator: đọc hợp đồng TRƯỚC, dò DOM là bước cuối.** Thứ tự bắt buộc (luật đầy đủ + lý do ở `/qc-design-script` §Role & stack — **không chép lại ở đây**):
27
27
 
28
- 1. **Test-id contract** — bảng *Test Selectors* §4.5.6 của tech-doc gộp, lọc theo cột "Phục vụ SC" khớp SC của UC này. TÊN thuộc tính đọc từ `@trace.testid_attr` ở header tech-doc (đừng suy từ platform).
28
+ 1. **Test-id contract** — bảng *Test Selectors* §4.5.6 của tech-doc gộp, lọc theo cột "Serves SC" khớp SC của UC này. TÊN thuộc tính đọc từ `@trace.testid_attr` ở header tech-doc (đừng suy từ platform).
29
29
  2. **Role + accessible name** — cho element có action mà §4.5.6 chưa phủ.
30
30
  3. **Dò DOM** — CHỈ khi 1 và 2 đều không định vị được. Dump class/`aria-label`/role bằng script tạm, rồi nhìn kết quả:
31
31
  - **3a. Element ĐÃ mang test-id trong code** → **DỪNG, đừng tự dùng id nhặt được.** Đây là ca *code đi trước hợp đồng*: chạy `/map-testids {UC-ID}` để đưa id đó vào §4.5.6 (nhánh `existing` — reverse-document), rồi quay lại bậc 1. Dùng thẳng là bỏ qua review, và id đó không bao giờ thành hợp đồng — lần sau lại phải đi khám phá lại.
@@ -41,7 +41,7 @@ Map nhóm GUI→`TestFeatureUI`, Functional→`TestFeatureFunctional`, Negative
41
41
  **Gom nhóm role/account**: thứ tự chạy đã tự gom cùng (role, account) liền nhau qua `utils/test_ordering.py` (hook ở root conftest) — fixture auth mới thì `register_auth_fixtures([...])`.
42
42
  ⚠️ Run dài có thể bị **WSL suspend** (máy ngủ) làm vài TC lỗi login/timeout = flaky (không phải gap SP) → re-run đúng các TC đó + merge vào report (xem `report/report.md`).
43
43
  **Verify KHÔNG còn Draft**: `grep -c "Status: Draft" <file>.Test.md` = 0 trước khi bàn giao.
44
- **Mỗi FAIL phân loại theo 3 nhãn — luật ở `/qc-run-test` §Chạy lại trước khi kết luận** (chạy lại ×2 trước, rồi người xác nhận; **không chép lại ở đây**). Đặc thù màn đơn: sai selector/expectation → `script-bug`, sửa script & chạy lại; feature không phản hồi sau timeout **và đỏ nhất quán qua các lần chạy lại** → `product-gap`, giữ FAIL + ghi bằng chứng (không fake-pass); timeout **chỉ xảy ra một số lần** → `flaky`, đừng ghi `fail`.
44
+ **Mỗi FAIL phân loại theo 3 nhãn — luật ở `/qc-run-script` §Chạy lại trước khi kết luận** (chạy lại ×2 trước, rồi người xác nhận; **không chép lại ở đây**). Đặc thù màn đơn: sai selector/expectation → `script-bug`, sửa script & chạy lại; feature không phản hồi sau timeout **và đỏ nhất quán qua các lần chạy lại** → `product-gap`, giữ FAIL + ghi bằng chứng (không fake-pass); timeout **chỉ xảy ra một số lần** → `flaky`, đừng ghi `fail`.
45
45
 
46
46
  ## Output
47
47
  Script `tests/<project>/.../test_<screen>.py` + Page Object `pages/<project>/.../<Screen>Page.py` (nếu mới).
@@ -58,4 +58,4 @@ Report = **Playwright Trace viewer + pytest-html** (KHÔNG Allure, KHÔNG dashbo
58
58
  - HTML report: `reports/<feature>/report.html` (self-contained, mở trực tiếp).
59
59
  - Trace từng test (debug step-by-step): `python3 -m playwright show-trace test-results/<nodeid>/trace.zip`.
60
60
  - Tóm tắt: **TOTAL / PASS / FAIL / SKIP** + duration.
61
- 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-test` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
61
+ 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-script` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
@@ -44,4 +44,4 @@ Report = **Playwright Trace viewer + pytest-html** (KHÔNG Allure, KHÔNG dashbo
44
44
  - HTML report: `reports/<feature>/report.html` (self-contained, mở trực tiếp).
45
45
  - Trace từng test (debug step-by-step): `python3 -m playwright show-trace test-results/<nodeid>/trace.zip`.
46
46
  - Tóm tắt: **TOTAL / PASS / FAIL / SKIP** + duration.
47
- 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-test` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
47
+ 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-script` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
@@ -46,4 +46,4 @@ Report = **Playwright Trace viewer + pytest-html** (KHÔNG Allure, KHÔNG dashbo
46
46
  - HTML report: `reports/<feature>/report.html` (self-contained, mở trực tiếp) + số đo thực tế.
47
47
  - Trace từng test (debug step-by-step): `python3 -m playwright show-trace test-results/<nodeid>/trace.zip`.
48
48
  - Tóm tắt: **TOTAL / PASS / FAIL / SKIP** + duration.
49
- 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-test` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu + số đo vào Status/khối kết quả của `.Test.md`.
49
+ 3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-script` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu + số đo vào Status/khối kết quả của `.Test.md`.
@@ -190,7 +190,7 @@ services:
190
190
  - Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
191
191
  - Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
192
192
  - Override `paths.prd_change_requests_dir` → `{spec_source}/feedback/prd-change-requests`
193
- - 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`.)*
193
+ - 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-script`) 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`.)*
194
194
  - 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`.)*
195
195
 
196
196
  > **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.
@@ -77,7 +77,7 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
77
77
 
78
78
  | Mức | Lệnh nào | `--yes` bỏ qua được? |
79
79
  |---|---|:---:|
80
- | **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
80
+ | **Không chặn** | `/review-code` · `/validate-traces` · `/debug` **KHÔNG phải vì read-only**: cả ba đều CÓ ghi file. Chúng không chặn vì thao tác ghi của chúng hoặc nằm sau một câu hỏi `(Y/N)`, hoặc nằm sau một cờ, hoặc là `append`/dựng-lại-được | — (vốn không có) |
81
81
  | **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
82
82
  | **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
83
83
 
@@ -85,6 +85,12 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
85
85
  `--` khỏi phần resolve target, nên cờ này không ảnh hưởng việc tìm file.) Mở đường chạy
86
86
  headless: `claude -p "/generate-code UC1 --yes"`.
87
87
 
88
+ > **Tên lệnh trong bảng trên có máy canh — `R19`.** Mỗi hàng bảng vừa nêu một mức vừa nêu
89
+ > tên lệnh sẽ bị đối chiếu với `gate.checkpoint_levels`; lệch là build đỏ. Lý do có rule này:
90
+ > ngày 2026-09-16 hai lệnh đổi mức, schema và `commands/*.tmpl` đều sửa, **build vẫn xanh**,
91
+ > mà bảng này lẫn `rules/workflow.md` đều còn liệt chúng ở mức cũ. `R11` chỉ canh
92
+ > `commands/*.tmpl` ↔ schema — *biết có máy canh không bằng biết máy canh **đến đâu***.
93
+
88
94
  > **KHÔNG tự suy mức từ bảng này.** Mỗi lệnh **tự khai** mức của nó ở một dòng `*Checkpoint: …*`
89
95
  > ngay dưới `## Gate` của chính nó — đọc dòng đó, đừng suy diễn. Bảng trên chỉ giải thích ba mức
90
96
  > **nghĩa là gì**.
@@ -99,21 +99,77 @@ Phạm vi QC — {TICKET-ID} / {active_platform}
99
99
  → {n} UC trong phạm vi · {m} chưa xét
100
100
  ```
101
101
 
102
- **Cờ `--include-draft`:** phân tích cả UC chưa duyệt, nhưng **vẫn in bảng trên** đánh dấu
103
- trong artifact là dựa trên BDD nháp.
102
+ **Cờ `--force`:** xử cả UC chưa duyệt, nhưng **vẫn in bảng trên**, in dòng khai đã bỏ qua gì,
103
+ và đánh dấu trong artifact là dựa trên BDD nháp. *(Tên cờ chung cho mọi chỗ "biết mà vẫn chạy" —
104
+ `rules/workflow.md` §Cờ bỏ qua điều kiện. Cờ cũ `--include-draft` đã bỏ, không có alias.)*
104
105
 
105
- **Không UC nào `approved` không`--include-draft` DỪNG:**
106
+ ### 4a Cổng cấp PRD:việc để làm không?
107
+
108
+ **Không UC nào `approved` và không có `--force` → DỪNG:**
106
109
  ```
107
110
  ❌ {TICKET-ID} ({active_platform}): 0/{n} UC có BDD approved — không có gì để chạy.
108
111
  Cách đúng: người duyệt đặt `# @trace.status: approved` rồi chạy lại.
109
- Muốn chạy sớm trên BDD nháp (prototype): thêm --include-draft
112
+ Muốn chạy sớm trên BDD nháp (prototype): thêm --force
113
+ ```
114
+
115
+ ### 4b — Cổng cấp UC: **cái UC vừa được gọi tên** có làm được không?
116
+
117
+ Bảy lệnh nhận target là **UC-ID** — `/qc-design-test` · `/qc-review-testcase` · `/qc-review-script` · `/qc-design-script` · `/qc-run-script` · `/qc-run-manualtest` · `/qc-report`
118
+ — phải đối chiếu target với **bảng vừa in ở trên**. Hai lệnh cấp PRD (`/qc-analyze` · `/qc-plan`)
119
+ **bỏ qua mục này**: target của chúng là `TICKET-ID`, và cổng 4a đã trả lời đúng câu hỏi của chúng.
120
+
121
+ | Target | Xử lý |
122
+ |---|---|
123
+ | Có trong `uc_list`, nhóm **Trong phạm vi** | đi tiếp |
124
+ | Có trong `uc_list`, nhóm **⏸ Chưa xét** | **DỪNG** — trừ khi có `--force` |
125
+ | **Không** có trong `uc_list` | **DỪNG** — sai UC-ID hoặc sai nền. **`--force` KHÔNG qua được** |
126
+
127
+ ```
128
+ ❌ {UC-ID} có BDD `{status}` — chưa approved, không nằm trong phạm vi QC pass này.
129
+ Cách đúng: người duyệt đặt `# @trace.status: approved` rồi chạy lại.
130
+ Cố ý làm sớm trên BDD nháp: thêm --force (artifact sẽ ghi rõ nó dựa trên bản nháp)
110
131
  ```
132
+ ```
133
+ ❌ {UC-ID} không có trong {TICKET-ID} ({active_platform}).
134
+ UC có mặt: {danh sách uc_list}
135
+ Kiểm lại UC-ID, hoặc UC này thuộc nền khác — nêu nền tường minh.
136
+ ```
137
+
138
+ > **Vì sao 4a không thay được 4b.** Điều kiện của 4a là **`0/n`** — *"cả PRD không có gì để chạy"*,
139
+ > đúng câu hỏi của một lệnh **cấp PRD**. Lệnh **cấp UC** hỏi câu khác hẳn. Với PRD `UC1 draft` +
140
+ > `UC2 approved`, cổng 4a thấy `1/2` → không phải `0/n` → **mở cửa**, và `/qc-design-test {UC1}`
141
+ > đi thẳng vào một spec chưa ai duyệt.
142
+ >
143
+ > Cái giá không dừng ở "thiết kế trên bản nháp". `Guard SC coverage` của trạm 3 sẽ **khẳng định**
144
+ > `khớp K/K` trên spec chưa duyệt, và `/qc-run-script` sẽ ghi `qc_status = pass` **chính thức** vào sổ
145
+ > trace cho nó. Đó là **báo cáo sai** — `rules/workflow.md` §*"ai KHẲNG ĐỊNH một giá trị dương phải
146
+ > được phép khẳng định"*.
147
+ >
148
+ > **Vì sao gộp luôn ca "UC-ID không có trong `uc_list`".** Cùng **một** phép so (`target ∈ nhóm
149
+ > Trong phạm vi`), và ca đó hiện **không ai bắt**: §1 đối chiếu `TICKET-ID` với tên file PRD thật và
150
+ > DỪNG nếu lệch, nhưng không có bước tương đương cho `UC-ID`. Gõ `/qc-design-test FT-001-UC7` khi PRD
151
+ > chỉ có UC1–UC3 thì không bước nào phát hiện.
152
+
153
+ ### Có `--force` thì artifact phải TỰ KHAI
154
+
155
+ In dòng khai ở report:
156
+ ```
157
+ ⚠️ --force: bỏ qua {điều kiện} — {UC-ID} @trace.status: {status}
158
+ ```
159
+ Và **mọi** file ghi ra trong lần chạy đó mang một dòng ở metadata:
160
+ ```
161
+ ⚠️ Dựa trên BDD NHÁP ({UC-ID} @trace.status: {status}) — spec có thể đổi.
162
+ ```
163
+
164
+ > **Vì sao cả hai chỗ.** Cờ nằm ở dòng lệnh thì **biến mất** sau khi lệnh chạy xong. Dòng ở report
165
+ > cho người đang ngồi đó; dòng trong file đi cùng file tới người đọc sau — người sẽ mở `.Test.md`
166
+ > ba tuần nữa và không có cách nào biết nó sinh ra từ bản nháp.
111
167
 
112
- > **Vì sao có `--include-draft` chứ không chặn cứng.** QC sớm trên BDD nháp là một cách dùng
113
- > **cố ý được cho phép** từ trước (guard cũ là cảnh báo mềm, không phải chặn). Bỏ hẳn nó là
114
- > lấy đi một năng lực đang có mà không ai khai. Còn để mặc định `approved`-only thì cái
115
- > thường gặp là cái an toàn, và cái sớm phải nói ra.
168
+ > **Vì sao có `--force` chứ không chặn cứng.** QC sớm trên BDD nháp là một cách dùng **cố ý được
169
+ > cho phép** từ trước (guard cũ là cảnh báo mềm, không phải chặn). Bỏ hẳn nó là lấy đi một năng lực
170
+ > đang có mà không ai khai. Còn để mặc định `approved`-only thì cái thường gặp là cái an toàn, và
171
+ > cái sớm phải nói ra.
116
172
 
117
- > **Vì sao `--yes` không thay được `--include-draft`.** `--yes` nghĩa *"tôi không ngồi đây để
118
- > trả lời"*; `--include-draft` nghĩa *"tôi biết BDD còn nháp và vẫn muốn chạy"*. Gộp hai cái
119
- > là để một lần chạy headless âm thầm phân tích spec chưa chốt rồi bàn giao như thể đã chốt.
173
+ > **Vì sao `--yes` không thay được `--force`.** `--yes` nghĩa *"tôi không ngồi đây để trả lời"*;
174
+ > `--force` nghĩa *"tôi biết BDD còn nháp và vẫn muốn chạy"*. Gộp hai cái là để một lần chạy headless
175
+ > âm thầm phân tích spec chưa chốt rồi bàn giao như thể đã chốt.
@@ -0,0 +1,142 @@
1
+ # QC artifact stamp — ghi mình sinh ra từ bản nào, và đọc cái người trước đã ghi
2
+
3
+ > Nguồn máy đọc: `bin/trace-schema.json` → `qc_artifact_stamp`. Đổi contract thì **sửa schema TRƯỚC**.
4
+ >
5
+ > **Hai vế, không tách.** Vế ghi (đóng dấu) và vế đọc (so dấu) phải cùng có mặt. Chỉ ghi mà không
6
+ > ai đọc là nhân thêm một con số vô dụng — `DOC_GAP.template.md` đã có sẵn cột `Phiên bản` như thế:
7
+ > được điền mỗi lần chạy, **0 consumer**.
8
+
9
+ ---
10
+
11
+ ## Vì sao tầng artifact QC cần cái này
12
+
13
+ `/generate-bdd` hạ `qc_status → not_run` khi spec đổi — đúng luật, và nó trả lời câu *"**kết quả chạy**
14
+ còn hiệu lực không?"*.
15
+
16
+ Câu chưa ai trả lời là *"**tài liệu thiết kế test** còn khớp không?"*. Hai câu dẫn tới hai việc khác nhau:
17
+
18
+ | Tín hiệu | Nghĩa | Việc phải làm |
19
+ |---|---|---|
20
+ | `qc_status = not_run` | kết quả cũ hết hiệu lực | **chạy lại** `/qc-run-script` |
21
+ | **stamp lệch** | TC/gap/plan mô tả spec cũ | **viết lại** — `/qc-analyze` hoặc `/qc-design-test` |
22
+
23
+ Thiếu vế sau thì người ta thấy `not_run` và **chạy lại** — đúng phản xạ, sai việc. Một bộ TC lỗi thời
24
+ chạy xanh ra `pass`, và `pass` đó **hợp lệ theo mọi phép kiểm hiện có**.
25
+
26
+ > **Vì sao phép kiểm nằm ở đây chứ không ở `/validate-traces`.** `qc_dir` là path QC **duy nhất
27
+ > không được remap** khi `setup.spec_source` được đặt — `specs_dir`, `tech_docs_dir`,
28
+ > `domain_knowledge_dir`, `trace_dir` đều remap, `qc_dir` ở lại `docs` của **repo QC**. Nên ở chế độ
29
+ > umbrella (`trace-mirror.md` gọi là *"trường hợp phổ biến"*), sổ trace và artifact QC nằm ở **hai
30
+ > repo khác nhau** và `/validate-traces` không với tới artifact QC.
31
+ >
32
+ > Các trạm QC thì **đã đọc cả hai** — artifact từ `{qc_artifact_dir}`, spec từ `{paths.specs_dir}`.
33
+ > Phép so nằm trong tầm với, không phải vượt repo.
34
+
35
+ ---
36
+
37
+ ## 1 — Khối stamp: ghi gì, ở đâu
38
+
39
+ Đặt ở **bảng metadata đầu file** (cả bốn artifact đều đã có bảng đó — đây là **thêm hàng**, không
40
+ phải dựng cấu trúc mới):
41
+
42
+ ```
43
+ | Nguồn & phiên bản | PRD `<vX.Y>` · tech-doc `<rev>` · design-spec `<vX.Y \| —>` |
44
+ | BDD theo UC | `<UC-ID>` `<vX.Y>` · `<UC-ID>` `<vX.Y>` … |
45
+ ```
46
+
47
+ **Lấy từng giá trị ở ĐÂU** — mỗi nguồn một định dạng khác nhau, đừng suy từ cái này sang cái kia:
48
+
49
+ | Giá trị | Lấy từ | Định dạng |
50
+ |---|---|---|
51
+ | `prd_version` | `\| **Version** \|` — bảng metadata đầu PRD | Markdown |
52
+ | **`bdd_version`** | **`@trace.bdd_version`** — header `.feature` | **Gherkin** — khối comment `# @trace.*`, **KHÔNG có bảng** |
53
+ | `tech_doc_revision` | `@trace.revision` — header tech-doc gộp | khối `@trace` |
54
+ | `design_spec_version` | `\| **Version** \|` — bảng metadata đầu design-spec | Markdown |
55
+ | `testid_attr` | `@trace.testid_attr` — header tech-doc | khối `@trace` |
56
+
57
+ > **Vì sao bảng này tồn tại** *(G85)*. Bản trước mô tả cả bốn nguồn bằng **một khuôn** —
58
+ > *"`| **Version** |` của header …"* — vì cả bốn "đều là tài liệu có metadata đầu file". Ba đúng,
59
+ > **một không thể đúng**: `.feature` là **Gherkin**, không có bảng Markdown nào. Đo thật: **0/278**
60
+ > file có dạng cũ, **276/278** có `@trace.bdd_version`.
61
+ >
62
+ > *Một khuôn cho N nguồn chỉ đúng khi N nguồn **cùng định dạng**. "Đều có metadata đầu file" không đủ.*
63
+
64
+ **Nguồn THIẾU → ghi `—` VÀ nói ra.** Đo thật: 2/278 `.feature` không có `@trace.bdd_version`.
65
+
66
+ ```
67
+ ⚠️ {UC-ID}: .feature thiếu @trace.bdd_version — stamp ghi '—', không so được ở trạm sau.
68
+ ```
69
+
70
+ **Đừng bỏ trống, đừng đoán.** Bỏ trống im lặng thì *"không lấy được"* trông **y hệt** *"artifact cũ
71
+ chưa có stamp"* — mà §2 bảo **đừng báo lệch** ở ca đó. Điều khoản tương thích ngược sẽ **nuốt luôn**
72
+ lỗi này. *(Cùng khuôn `@trace.testid_attr` của `/qc-design-test` đã dùng.)*
73
+
74
+ | Artifact | Ai ghi | Stamp gì |
75
+ |---|---|---|
76
+ | `REQUIREMENT_ANALYSIS.md` · `DOC_GAP.md` | `/qc-analyze` | `prd_version` · `bdd_version` **theo từng UC** · `tech_doc_revision` · `design_spec_version` |
77
+ | `TEST_PLAN.md` | `/qc-plan` | **chép lại** stamp của `DOC_GAP.md` |
78
+ | `test-cases/*.Test.md` | `/qc-design-test` | `bdd_version` của UC này · `tech_doc_revision` · `@trace.testid_attr` |
79
+
80
+ **`bdd_version` phải theo TỪNG UC.** `DOC_GAP.md` và `REQUIREMENT_ANALYSIS.md` phủ **cả PRD**, mà mỗi
81
+ UC là một file `.feature` riêng với version riêng — một số duy nhất cho cả file sẽ **sai cho `n−1` UC**.
82
+
83
+ **`/qc-plan` CHÉP LẠI, không tự đi lấy.** Nó không đọc spec trực tiếp (đầu vào của nó là output trạm 1).
84
+ Tự đi lấy là tạo **hai nguồn cho một số**, rồi chúng lệch nhau — và lúc đó không ai biết bên nào đúng.
85
+
86
+ ---
87
+
88
+ ## 2 — Phép so: đọc dấu người trước đã ghi
89
+
90
+ Chạy **ngay sau guard tiền đề** (phần "có file không?"), trước mọi việc khác. Guard tiền đề hỏi
91
+ *"có không?"*; bước này hỏi *"còn khớp không?"*.
92
+
93
+ Với mỗi artifact mà lệnh này đọc:
94
+
95
+ 1. Đọc khối stamp của nó.
96
+ 2. Đọc version **hiện tại** của các nguồn tương ứng (`.feature` của UC · PRD · tech-doc · design-spec).
97
+ 3. So từng cặp.
98
+
99
+ | Kết quả | Xử lý |
100
+ |---|---|
101
+ | Khớp hết | **im lặng, đi tiếp** |
102
+ | **Không có khối stamp** | `⚠️ {file}: chưa có stamp (sinh trước G63) — chạy lại {lệnh} để đóng dấu.` **KHÔNG báo lệch** |
103
+ | Lệch | theo bảng mức dưới đây |
104
+
105
+ > **Điều khoản tương thích ngược là bắt buộc, không phải lịch sự.** Artifact sinh ra trước khi có
106
+ > contract này thì đương nhiên không có stamp. Báo "lệch" ở đó là **bắt oan mọi dự án đang chạy ngay
107
+ > ngày nâng version** — và việc đầu tiên người ta làm là tìm cách tắt cảnh báo. Cùng điều khoản mà
108
+ > `testid_contract` đã dùng: *"doc không có block §4.5 client thì KHÔNG kiểm gì"*.
109
+
110
+ ### Mức phản ứng — KHÔNG đồng nhất
111
+
112
+ | Trạm | Lệch thì | Vì sao |
113
+ |---|---|---|
114
+ | `/qc-plan` · `/qc-design-test` · `/qc-review-testcase` | **⚠️ cảnh báo, đi tiếp** | Cùng họ `TECHDOC_DRIFT`/`BDD_DRIFT` — 13/17 cờ audit không chặn. Thiết kế TC trên bản hơi cũ vẫn ra sản phẩm dùng được; chặn ở đây là **ồn** |
115
+ | `/qc-run-script` | **chặn `pass`, KHÔNG chặn chạy** | Lớp **báo cáo sai** |
116
+
117
+ ```
118
+ ⚠️ Stamp lệch — {file} dựng trên {nguồn} {ver_cũ}, hiện tại {ver_mới}.
119
+ UC ảnh hưởng: {danh sách}
120
+ Nên chạy lại: {lệnh} (đi tiếp vẫn được, nhưng {hệ quả cụ thể})
121
+ ```
122
+
123
+ **`/qc-run-script` — nhập vào cơ chế đã có, không phát minh cơ chế mới.** Stamp lệch xử lý **y hệt**
124
+ row `DRIFT`/`ORPHANED` của `positive_assertion_guards` + lint **T12** (G55): test vẫn chạy, nhưng
125
+ xanh → ghi `not_run` chứ **không** ghi `pass`, và **không đóng bug nào** ở lần chạy đó.
126
+
127
+ > **`fail` vẫn ghi `fail` bình thường.** Đây là guard chống **báo cáo sai**, không phải guard **che
128
+ > tin xấu** — nguyên văn lập luận của `positive_assertion_guards`.
129
+
130
+ ---
131
+
132
+ ## 3 — Phép so đi theo từng UC, không theo cả file
133
+
134
+ Bump `bdd_version` của **UC2** thì `/qc-design-test {UC1}` phải **im lặng hoàn toàn**.
135
+
136
+ Trạm 3–5 chạy **per-UC**, nhiều lần cho mỗi PRD. Một cảnh báo báo oan ở đây không chỉ sai một lần —
137
+ nó lặp lại mỗi lần chạy, và cảnh báo lặp mà không đúng là cách nhanh nhất để người ta ngừng đọc **mọi**
138
+ cảnh báo của lệnh này.
139
+
140
+ Nên khi so `DOC_GAP.md` / `REQUIREMENT_ANALYSIS.md` (phủ cả PRD): **chỉ lấy hàng `bdd_version` của UC
141
+ đang chạy** để so. `prd_version` / `tech_doc_revision` / `design_spec_version` là số chung cả PRD nên
142
+ so trực tiếp.