@educa-corp/sdd-framework 0.9.4 → 0.9.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.
Files changed (104) hide show
  1. package/bin/build.js +11 -1
  2. package/bin/lint-trace.js +599 -2
  3. package/bin/self-check.js +195 -0
  4. package/bin/trace-schema.json +2656 -1927
  5. package/core/FRAMEWORK_VERSION +1 -1
  6. package/core/commands/dev-gen-test.md +62 -0
  7. package/core/commands/generate-bdd.md +1 -0
  8. package/core/commands/generate-code.md +39 -2
  9. package/core/commands/generate-tech-docs.md +24 -5
  10. package/core/commands/map-testids.md +164 -7
  11. package/core/commands/qc-analyze.md +163 -9
  12. package/core/commands/qc-design-test.md +294 -2
  13. package/core/commands/qc-plan.md +57 -3
  14. package/core/commands/qc-report.md +76 -60
  15. package/core/commands/qc-review.md +102 -1
  16. package/core/commands/qc-run-test.md +194 -5
  17. package/core/commands/review-tech-docs.md +20 -0
  18. package/core/commands/validate-traces.md +17 -2
  19. package/core/modules/qc-playwright/stack-profile.yaml +1 -1
  20. package/core/rules/data-protection.md +52 -0
  21. package/core/rules/workflow.md +40 -0
  22. package/core/skills/qc/_shared/self-review-principles.md +112 -0
  23. package/core/skills/qc/qa-analyst/DOC_GAP.template.md +9 -1
  24. package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +33 -5
  25. package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +24 -0
  26. package/core/skills/qc/qa-planner/test-plan.md +7 -0
  27. package/core/skills/qc/qa-runner/e2e.md +2 -2
  28. package/core/skills/qc/qa-runner/functional/gui-feature.md +9 -3
  29. package/core/skills/qc/qa-runner/functional/gui-screen.md +9 -3
  30. package/core/skills/qc/qa-runner/integration.md +1 -1
  31. package/core/skills/qc/qa-runner/non-functional.md +1 -1
  32. package/core/skills/spec/SKILL.md +1 -1
  33. package/core/steps/context-loader.md +7 -2
  34. package/core/steps/gap-verify.md +67 -0
  35. package/core/steps/qc-scope.md +67 -11
  36. package/core/steps/qc-stamp.md +142 -0
  37. package/core/steps/report-footer.md +15 -7
  38. package/core/templates/feature.template +1 -0
  39. package/core/templates/tech-design.template.md +4 -3
  40. package/docs/01-getting-started/quickstart.md +4 -3
  41. package/docs/02-concepts/architecture.md +14 -0
  42. package/docs/02-concepts/glossary.md +8 -0
  43. package/docs/02-concepts/overview.md +3 -2
  44. package/docs/02-concepts/pipeline-steps/04-bdd.md +1 -1
  45. package/docs/02-concepts/pipeline-steps/05-tech-docs.md +21 -5
  46. package/docs/02-concepts/pipeline-steps/06-code.md +12 -2
  47. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +60 -12
  48. package/docs/02-concepts/pipeline-steps/README.md +4 -3
  49. package/docs/02-concepts/traceability.md +2 -2
  50. package/docs/03-guides/architect.md +2 -2
  51. package/docs/03-guides/developer.md +5 -2
  52. package/docs/03-guides/tester-qa.md +17 -5
  53. package/docs/04-reference/commands.md +7 -4
  54. package/docs/04-reference/trace-schema.md +38 -0
  55. package/docs/explain/07-generate-tech-docs.md +5 -3
  56. package/docs/explain/08-review-tech-docs.md +15 -3
  57. package/docs/explain/09-generate-code.md +30 -4
  58. package/docs/explain/10-review-code.md +1 -1
  59. package/docs/explain/11-map-testids.md +10 -7
  60. package/docs/explain/12-dev-gen-test.md +1 -1
  61. package/docs/explain/15-qc-analyze.md +14 -2
  62. package/docs/explain/16-qc-plan.md +5 -1
  63. package/docs/explain/17-qc-design-test.md +26 -3
  64. package/docs/explain/18-qc-review.md +6 -2
  65. package/docs/explain/19-qc-run-test.md +29 -6
  66. package/docs/explain/20-qc-report.md +5 -2
  67. package/docs/explain/README.md +4 -1
  68. package/docs/plans/qc-surgery/00-nhat-ky.md +497 -0
  69. package/docs/plans/qc-surgery/01-checklist.md +92 -0
  70. package/docs/plans/qc-surgery/02-lo-trinh.md +266 -0
  71. package/docs/plans/qc-surgery/buoc/0-01-testid-attr-co-cho-o.md +157 -0
  72. package/docs/plans/qc-surgery/buoc/0-02-mot-nguon-cho-testid-attr.md +135 -0
  73. package/docs/plans/qc-surgery/buoc/0-03-skill-thoi-day-do-dom.md +167 -0
  74. package/docs/plans/qc-surgery/buoc/0-04-may-canh-hop-dong.md +173 -0
  75. package/docs/plans/qc-surgery/buoc/0-05-don-nhan-cot-va-2b.md +133 -0
  76. package/docs/plans/qc-surgery/buoc/0-06-hop-dong-truoc-code.md +226 -0
  77. package/docs/plans/qc-surgery/buoc/1-01-guard-br-tag.md +156 -0
  78. package/docs/plans/qc-surgery/buoc/1-02-guard-sc-coverage.md +153 -0
  79. package/docs/plans/qc-surgery/buoc/1-03-fail-3-nhan.md +176 -0
  80. package/docs/plans/qc-surgery/buoc/1-04-self-review-dung-chung.md +175 -0
  81. package/docs/plans/qc-surgery/buoc/1-05-spec-la-du-lieu.md +164 -0
  82. package/docs/plans/qc-surgery/buoc/1-06-gap-verify-du-bo.md +162 -0
  83. package/docs/plans/qc-surgery/buoc/README.md +85 -0
  84. package/docs/plans/qc-surgery/exec-d0-b1-testid-attr-header.md +147 -0
  85. package/docs/plans/qc-surgery/exec-d0-b2-thong-nhat-nguon-testid-attr.md +152 -0
  86. package/docs/plans/qc-surgery/exec-d0-b3-sua-skill-probe-dom.md +173 -0
  87. package/docs/plans/qc-surgery/exec-d0-b4-may-canh-4-5-6.md +168 -0
  88. package/docs/plans/qc-surgery/exec-d0-b5-don-nhan-lech.md +196 -0
  89. package/docs/plans/qc-surgery/exec-d0-b6-contract-truoc-code.md +350 -0
  90. package/docs/plans/qc-surgery/exec-d1-b1-guard-br-tag.md +129 -0
  91. package/docs/plans/qc-surgery/exec-d1-b2-guard-sc-coverage.md +159 -0
  92. package/docs/plans/qc-surgery/exec-d1-b3-fail-3-bucket.md +158 -0
  93. package/docs/plans/qc-surgery/exec-d1-b4-self-review-principles.md +145 -0
  94. package/docs/plans/qc-surgery/exec-d1-b5-noi-quy-spec-la-du-lieu.md +156 -0
  95. package/docs/plans/qc-surgery/exec-d1-b6-gap-verify-mo-rong.md +179 -0
  96. package/docs/plans/qc-surgery/exec-d2-b1-tach-qc-review.md +166 -0
  97. package/docs/plans/qc-surgery/exec-d2-b2-tach-qc-run-test-atomic.md +267 -0
  98. package/docs/plans/qc-surgery/exec-d2-b3-qc-automation-assess.md +198 -0
  99. package/docs/plans/qc-surgery/exec-d3-b1-qc-report-gate-decision.md +209 -0
  100. package/docs/plans/qc-surgery/exec-d4-b1-qc-design-testdata.md +146 -0
  101. package/docs/plans/qc-surgery/exec-d4-b2-qc-smoke-test.md +179 -0
  102. package/docs/plans/qc-surgery/exec-d4-b3-qc-metrics-va-lint.md +198 -0
  103. package/docs/plans/qc-surgery/exec-d4-b4-lint-spec-injection.md +199 -0
  104. package/package.json +1 -1
@@ -0,0 +1,166 @@
1
+ ---
2
+ buoc: Đợt 2 — Bước 1
3
+ title: Tách /qc-review thành /qc-review-testcase và /qc-review-script
4
+ phu_thuoc: Đợt 1 xong
5
+ trang_thai: chưa làm
6
+ ---
7
+
8
+ # Đợt 2 · Bước 1 — Một lệnh hai vai, không ai biết đang gọi vai nào
9
+
10
+ ← [`01-checklist.md`](01-checklist.md) · [`02-lo-trinh.md`](02-lo-trinh.md)
11
+
12
+ ## 1. Vì sao
13
+
14
+ `/qc-review` hiện là **một lệnh làm hai việc khác nhau ở hai thời điểm khác nhau**:
15
+
16
+ ```
17
+ sau /qc-design-test → soát test case (.Test.md) — coverage, độ rõ, trace
18
+ sau /qc-run-test → soát code test (Python/PO) — locator, assertion, hard-code
19
+ ```
20
+
21
+ Cách lệnh biết nó đang làm vai nào: **tự đoán**. Nguyên văn `commands/qc-review.tmpl:41-42`:
22
+
23
+ > *"Phát hiện mode: nếu artifact target là `.Test.md` → review test-case; nếu file Python
24
+ > test/PO tồn tại cho UC và mới hơn → review script. Nếu mơ hồ, hỏi."*
25
+
26
+ Ba vấn đề với việc đoán:
27
+
28
+ 1. **Điều kiện "mới hơn" là một phép so ngày tháng, không phải ý định.** Sửa một dòng trong file
29
+ test hôm nay rồi gọi `/qc-review` để soát lại **test case** → lệnh chọn vai script.
30
+ 2. **Người chạy không biết mình đã gọi vai nào cho tới khi đọc kết quả.** Bộ tiêu chí hai vai
31
+ khác nhau hoàn toàn (`skills/qc/qa-reviewer/test-case/*` vs `script/*`).
32
+ 3. **Không đặt được điều kiện tiên quyết cho trạm sau.** Đây là hậu quả nặng nhất: `/qc-run-test`
33
+ không thể hỏi *"test case đã APPROVED chưa?"* vì không phân biệt được `REVIEW_<FEATURE>.md`
34
+ là kết quả soát test case hay soát script.
35
+
36
+ Chính file lệnh cũng ghi rõ hai vai không được lẫn — `:57`:
37
+
38
+ > *"gắn nhãn lỗi cho thứ đáng lẽ không có ở đó. Vai 2 dùng bộ tiêu chí riêng ở `script/*.md`."*
39
+
40
+ Đã biết là hai vai riêng, dùng tiêu chí riêng, chỉ còn thiếu việc gọi tên riêng.
41
+
42
+ ## 2. Tình trạng hiện tại
43
+
44
+ **Lệnh tự khai là "gate hai chiều"** — `commands/qc-review.tmpl:9`:
45
+
46
+ > *"Một gate hai chiều: review test case (sau qc-design-test) VÀ script (sau qc-run-test)."*
47
+
48
+ **Hai bộ skill đã tách sẵn** — `:60-61`:
49
+
50
+ ```
51
+ - Soát test-case: test-case/{functional,e2e,integration,non-functional,exploratory}.md
52
+ - Soát script: script/{functional,e2e,integration,non-functional,exploratory}.md
53
+ ```
54
+
55
+ **Tin tốt — bước này rẻ nhất trong cả Đợt 2:**
56
+
57
+ ```bash
58
+ grep -c '"qc-review"' bin/trace-schema.json
59
+ # → 0
60
+ ```
61
+
62
+ `/qc-review` **không ghi cột trace nào**, nên nó không có trong `actors`, không có trong
63
+ `tsv_columns.written_by`, không có trong `positive_assertion_guards`. Tách nó **không đụng
64
+ schema** → không gặp ràng buộc nguyên tử của `bin/self-check.js` (R3/R14/R15) như bước 2.
65
+
66
+ ## 3. Sẽ đổi thành gì
67
+
68
+ ### 3.1 Hai lệnh, mỗi lệnh một vai
69
+
70
+ | Lệnh mới | Soát gì | Skill dùng | Chạy khi nào |
71
+ |---|---|---|---|
72
+ | `/qc-review-testcase` | `.Test.md` — coverage, độ rõ, trace | `qa-reviewer/test-case/*` | sau `/qc-design-test` |
73
+ | `/qc-review-script` | code test + Page Object | `qa-reviewer/script/{web,mobile}/*` | sau `/qc-design-script` (Đợt 2 bước 2) |
74
+
75
+ Bỏ hẳn phần tự đoán mode. Không còn `:41-42`.
76
+
77
+ ### 3.2 Verdict thành điều kiện tiên quyết — đây là phần có giá trị thật
78
+
79
+ Mỗi lệnh ghi verdict rõ ràng vào `REVIEW_<FEATURE>.md`: **`APPROVED`** hoặc **`NEEDS_FIX`**.
80
+
81
+ Và trạm sau **đọc verdict rồi mới chạy**:
82
+
83
+ ```
84
+ /qc-automation-assess ← chỉ nhận TC có REVIEW verdict = APPROVED
85
+ TC còn Draft hoặc NEEDS_FIX → loại khỏi lượt, liệt kê ra
86
+ /qc-run-script ← đọc verdict của /qc-review-script;
87
+ NEEDS_FIX hoặc chưa có → DỪNG, báo chạy /qc-review-script trước
88
+ ```
89
+
90
+ Đây là điều `/qc-review` hiện **không làm được**, và là lý do chính để tách.
91
+
92
+ *(Hai trạm tiêu thụ này thuộc bước 2 và 3 của Đợt 2. Ở bước 1 chỉ cần ghi verdict đúng định
93
+ dạng; phần đọc verdict làm ở bước sau.)*
94
+
95
+ ### 3.3 Thay 4 skill soát script dạng phẳng bằng web/mobile
96
+
97
+ Hiện `skills/qc/qa-reviewer/script/` có 5 file phẳng: `e2e.md`, `functional.md`,
98
+ `integration.md`, `non-functional.md`, `exploratory.md`. Stack mới có 2 nền (web Playwright /
99
+ mobile WebdriverIO) với tiêu chí khác nhau → thay bằng cấu trúc của đề xuất:
100
+
101
+ ```
102
+ qa-reviewer/script/
103
+ ├── web/ { e2e, functional, functional/api, integration, non-functional }
104
+ ├── mobile/ { e2e, functional, integration, non-functional }
105
+ └── exploratory.md ← giữ nguyên, không theo nền
106
+ ```
107
+
108
+ **Kiểm trước khi gỡ 4 file cũ:** không có entry `ported` nào trong `bin/qc-base-map.json` cho
109
+ chúng → gỡ **không** trip R16(c) (*"target của entry `ported` phải tồn tại"*). Đã xác nhận bằng
110
+ cách quét bản đồ.
111
+
112
+ ## 4. Sửa file nào
113
+
114
+ | File | Sửa gì |
115
+ |---|---|
116
+ | `commands/qc-review-testcase.tmpl` | **Mới** — dùng `{{include:steps/gate.md}}`, `{{include:steps/qc-scope.md}}`; khai nhãn `*Checkpoint:*` |
117
+ | `commands/qc-review-script.tmpl` | **Mới** — tương tự |
118
+ | `commands/qc-review.tmpl` + `.md` | **Gỡ** |
119
+ | `skills/qc/qa-reviewer/script/{e2e,functional,integration,non-functional}.md` | **Gỡ**, thay bằng `script/{web,mobile}/*` từ đề xuất |
120
+ | `skills/qc/qa-reviewer/script/exploratory.md` | Giữ |
121
+ | `steps/report-footer.md` | Bảng Phase + bảng Next — thay `/qc-review` bằng 2 lệnh mới |
122
+ | `docs/explain/18-qc-review.md` | Tách thành 2 mục, hoặc đổi tên file |
123
+ | `docs/04-reference/commands.md` | Cập nhật bảng lệnh |
124
+ | `bin/qc-base-map.json` | Entry cho skill `script/{web,mobile}/*` mới |
125
+
126
+ Nguồn nội dung: `D:\base\qcframework_proposal\command\qc-review-testcase.md` và
127
+ `qc-review-script.md` — **viết lại thành `.tmpl`**, thay gate cắt tay (5.4 KB của họ) bằng
128
+ `{{include:steps/gate.md}}` (11.1 KB thật). Gỡ khối comment provenance 10+ dòng ở đầu file, đưa
129
+ vào `bin/qc-base-map.json`.
130
+
131
+ ## 5. Kiểm thế nào để biết đã xong
132
+
133
+ ```bash
134
+ # 1. Không còn dấu vết lệnh cũ
135
+ ls commands/qc-review.* # → không tồn tại
136
+ grep -rn "/qc-review\b" commands/ steps/ docs/ rules/ | grep -v "qc-review-testcase\|qc-review-script"
137
+ # → 0 kết quả (trừ file GAPS lịch sử)
138
+
139
+ # 2. Hai lệnh mới có nhãn Checkpoint và include gate thật
140
+ grep -n "Checkpoint:" commands/qc-review-testcase.tmpl commands/qc-review-script.tmpl
141
+ grep -n "{{include:steps/gate.md}}" commands/qc-review-testcase.tmpl commands/qc-review-script.tmpl
142
+
143
+ # 3. Mọi tham chiếu skill trỏ tới file có thật (R16d) + shortcut được sinh
144
+ node bin/build.js && node bin/self-check.js && node test/run.js
145
+ ls core/commands/qc-review-*.md # → 2 file
146
+ ```
147
+
148
+ Kiểm bằng tay:
149
+
150
+ 1. `/qc-review-testcase {UC-ID}` → soát `.Test.md`, ghi `REVIEW_<FEATURE>.md` với verdict rõ
151
+ ràng. Phải **không** đi tìm file code test.
152
+ 2. `/qc-review-script {UC-ID}` → soát code test. Phải **không** đi soát `.Test.md`.
153
+ 3. `/qc-review {UC-ID}` → phải báo lệnh không tồn tại (đã gỡ).
154
+
155
+ ## 6. Nếu bỏ qua thì hỏng gì
156
+
157
+ **Bước 2 và 3 của Đợt 2 mất phần chặn của chúng.** `/qc-run-script` được thiết kế để **DỪNG** khi
158
+ script chưa `APPROVED`; `/qc-automation-assess` để **loại** TC chưa `APPROVED` khỏi lượt đánh
159
+ giá. Cả hai đọc verdict — mà verdict của `/qc-review` hiện không nói nó thuộc vai nào. Nên nếu
160
+ không tách, hai cơ chế chặn đó không dựng được, và pipeline mới mất đúng hai điểm kiểm soát mà
161
+ nó thêm vào so với pipeline cũ.
162
+
163
+ Thêm nữa: `/qc-review` hiện đọc `.Test.md` **và** code Python. Đợt 2 bước 2 đổi stack sang
164
+ TypeScript. Lệnh hai vai sẽ phải mang cả hai bộ tiêu chí cho cả hai nền (web + mobile) trong
165
+ một file — tức là bốn bộ tiêu chí trong một lệnh, và phép đoán mode phải đoán thêm một chiều
166
+ nữa. Tách trước là để không phải viết cái đó.
@@ -0,0 +1,267 @@
1
+ ---
2
+ buoc: Đợt 2 — Bước 2
3
+ title: Tách /qc-run-test thành 3 lệnh — MỘT COMMIT DUY NHẤT
4
+ phu_thuoc: d2-b1
5
+ trang_thai: chưa làm
6
+ canh_bao: commit nguyên tử, ~30 file
7
+ ---
8
+
9
+ # Đợt 2 · Bước 2 ⚠️ — Commit lớn nhất của cả đợt mổ
10
+
11
+ ← [`01-checklist.md`](01-checklist.md) · [`02-lo-trinh.md`](02-lo-trinh.md)
12
+
13
+ > **Đọc §3.1 trước khi bắt tay.** Bước này **không chia nhỏ được** — nếu tách thành nhiều commit
14
+ > thì commit ở giữa sẽ làm `node bin/self-check.js` đỏ. Làm trên branch riêng.
15
+
16
+ ## 1. Vì sao
17
+
18
+ ### 1.1 Một lệnh gánh bốn việc
19
+
20
+ `/qc-run-test` hiện làm:
21
+
22
+ ```
23
+ 1. quyết định test nào automate được ← ngầm định: TẤT CẢ
24
+ 2. viết code test + Page Object
25
+ 3. chạy test
26
+ 4. phán "fail này là lỗi sản phẩm hay lỗi code test" → ghi qc_status
27
+ ```
28
+
29
+ Bốn việc, bốn loại quyết định, **không có chỗ nào dừng lại giữa chúng**. Hậu quả cụ thể:
30
+
31
+ - Không thể review code test **trước khi** chạy — lúc lệnh chạy xong thì code đã chạy rồi.
32
+ - Không thể sửa code test rồi chạy lại **mà không sinh lại từ đầu**.
33
+ - Việc số 1 không tồn tại như một bước, nên TC không automate được (OTP, captcha, thiết bị thật)
34
+ bị ép sinh script, rồi `pytest.skip` — và biến mất khỏi tầm nhìn.
35
+
36
+ ### 1.2 Lỗ hổng test tay — lý do có lệnh thứ ba
37
+
38
+ Đề xuất của chị QC tách thành 2 lệnh (`design-script` + `run-script`). Nhưng như vậy còn thiếu
39
+ một chỗ: **ai ghi kết quả cho TC không automate được?**
40
+
41
+ `/qc-automation-assess` (bước 3) đóng dấu `Automatable: N` và nói *"giữ trong bộ manual"*. Rồi
42
+ hết. Không trạm nào chạy và ghi `qc_status` cho chúng.
43
+
44
+ Đến Đợt 3, `/qc-report` tính:
45
+
46
+ ```
47
+ Execution coverage = số SC có qc_status ∈ {pass, fail} / tổng số SC
48
+ Ngưỡng: coverage_min = 85 not_run_p0_max = 0
49
+ ```
50
+
51
+ Ví dụ PRD "Đăng nhập" 5 scenario, trong đó SC4 (OTP qua SMS, **P0**) và SC5 (sinh trắc học) phải
52
+ test tay:
53
+
54
+ ```
55
+ SC1 pass ← /qc-run-script ghi
56
+ SC2 pass ← /qc-run-script ghi
57
+ SC3 pass ← /qc-run-script ghi
58
+ SC4 not_run ← KHÔNG AI GHI. QC đã test tay, thấy OK, nhưng không có chỗ ghi lại
59
+ SC5 not_run ← KHÔNG AI GHI
60
+
61
+ → Execution coverage = 3/5 = 60% < 85 ❌
62
+ → SC P0 not_run = 1 > 0 ❌
63
+ → VERDICT: FAIL ...và FAIL vĩnh viễn, không có cách nào sửa
64
+ ```
65
+
66
+ Nghịch lý: bước 3 **cho phép** đóng dấu `N`, Đợt 3 **trừng phạt** chính dấu đó. Hai trạm cùng
67
+ pipeline nói ngược nhau.
68
+
69
+ Nên thêm lệnh thứ ba: **`/qc-run-manualtest`** (tên do anh chọn).
70
+
71
+ Bonus: đề xuất định **gỡ** 9 skill `skills/qc/qa-runner/**` — đó đúng là bộ hướng dẫn chạy test
72
+ theo từng loại (màn hình, API, integration, exploratory session). `/qc-run-manualtest` dùng lại
73
+ chúng, nên **giữ**.
74
+
75
+ ## 2. Tình trạng hiện tại
76
+
77
+ **Lệnh gộp** — `commands/qc-run-test.tmpl:7-9`:
78
+
79
+ > *"# /qc-run-test — QC Script Generation & Run (ghi qc_status)"*
80
+ > *"Sinh & chạy Python pytest-playwright từ `.Test.md` đã review, rồi ghi `qc_status` **chính
81
+ > thức** vào trace TSV."*
82
+
83
+ **Nó là chủ duy nhất của 4 cột trace** — `bin/trace-schema.json`:
84
+
85
+ | Cột | `qc-run-test` là | Dòng |
86
+ |---|---|---|
87
+ | 10 `qc_status` | **chủ ghi** (`"Chủ (ghi pass/fail/skip): qc-run-test — DUY NHẤT"`) | :785, :787 |
88
+ | 11 `qc_run_at` | chủ ghi | :804 |
89
+ | 12 `qc_owner` | chủ ghi | :818 |
90
+ | 13 `qc_blocked_by` | chủ ghi + đọc | :831, :837 |
91
+
92
+ Và nó xuất hiện **21 chỗ** trong schema:
93
+
94
+ | Khối | Số chỗ | Dòng |
95
+ |---|:---:|---|
96
+ | `actors` | 1 | :31 |
97
+ | `tags` | 3 | :197, :204, :480 |
98
+ | `tsv_columns` (`written_by`/`read_by`) | 10 | :666, :764, :779, :787, :804, :818, :831, :837, :933, :1004 |
99
+ | `queues` | 1 | :1060 |
100
+ | `positive_assertion_guards` → `owner` | 1 | :1769 |
101
+ | `strict_use_check` → `actors` | 1 | :1821 |
102
+ | Văn xuôi giải thích (`$comment`, `$history_note`, `why`) | 4 | :483, :484, :785, :802 |
103
+
104
+ ## 3. Sẽ đổi thành gì
105
+
106
+ ### 3.1 ⚠️ Vì sao phải là MỘT commit
107
+
108
+ `bin/self-check.js` phân giải tên lệnh → file nguồn ở ba rule:
109
+
110
+ ```js
111
+ // bin/self-check.js:1050 (R14 — positive_assertion_guards)
112
+ const rel = `commands/${g.owner}.tmpl`;
113
+ if (!fs.existsSync(abs)) err('R14', `khai chủ cột ... là ${g.owner} — ${rel} không tồn tại`);
114
+
115
+ // bin/self-check.js:1159 (R15 — strict_use_check)
116
+ const rel = schema.actors[actor] || `commands/${actor}.tmpl`;
117
+ if (!fs.existsSync(abs)) err('R15', `khai actor ${actor} — ${rel} không tồn tại`);
118
+ ```
119
+
120
+ Nên:
121
+
122
+ | Nếu làm | Kết quả |
123
+ |---|---|
124
+ | Đổi tên file trước, sửa schema sau | Commit giữa: schema trỏ `commands/qc-run-test.tmpl` không còn tồn tại → **R14 + R15 đỏ** |
125
+ | Sửa schema trước, đổi tên file sau | Commit giữa: schema trỏ `commands/qc-run-script.tmpl` chưa tồn tại → **R14 + R15 đỏ** |
126
+
127
+ Không có thứ tự nào an toàn. Nguyên tắc số 1 của đợt mổ (*mỗi commit đều xanh*) buộc gộp thành
128
+ một.
129
+
130
+ **Thêm một ràng buộc của R14:** file chủ cột phải **nhắc từng status bị chặn**. `bin/self-check.js`
131
+ đọc `positive_assertion_guards.blocked_when_status = ["DRIFT", "ORPHANED"]` rồi kiểm file chủ có
132
+ nhắc **cả hai token** — bằng `mentions()` (khớp ranh giới token, không phải `includes()`). Nên cả
133
+ `/qc-run-script` **và** `/qc-run-manualtest` đều phải có đoạn guard nhắc rõ `DRIFT` và
134
+ `ORPHANED`. Đề xuất đã có đoạn đó cho `run-script`; phải viết thêm cho `run-manualtest`.
135
+
136
+ ### 3.2 Ba lệnh mới
137
+
138
+ | Lệnh | Việc | Ghi trace? |
139
+ |---|---|---|
140
+ | `/qc-design-script` | Viết code test + Page Object cho TC `Automatable: Y`. Sinh **Testability Improvement List** (`IMPROVE-{date}-{NN}`) khi gặp rào cản kỹ thuật. Đọc `Priority` → gắn tag `@smoke`/`@regression`. Điền cột `Script file` của `AUTOMATION_ASSESSMENT.md` | Không |
141
+ | `/qc-run-script` | Chạy code test đã `APPROVED`. Chạy lại ×2 → phân loại 3 loại → người xác nhận → ghi `qc_status` | **Có** — chủ cột 10–13 |
142
+ | `/qc-run-manualtest` | QC chạy tay TC `Automatable: N`, ghi kết quả vào sổ trace. Dùng lại `skills/qc/qa-runner/**` | **Có** — chủ cột 10–13 |
143
+
144
+ **Hai chủ cho cùng bốn cột** là điều mới. Cần khai đúng trong `positive_assertion_guards`
145
+ (`owner` hiện là một chuỗi, có thể phải thành mảng — kiểm cấu trúc rồi sửa `self-check.js:1050`
146
+ cho khớp nếu cần).
147
+
148
+ ### 3.3 `/qc-run-manualtest` — điểm còn phải chốt với chị QC
149
+
150
+ Chưa chốt: **cách nhập kết quả**. Hai phương án:
151
+
152
+ | | Cách | Ưu | Nhược |
153
+ |---|---|---|---|
154
+ | A | Lệnh hỏi từng TC `Automatable: N`: pass/fail/skip + ghi chú | Không cần file trung gian; nhắc đủ TC | Nhiều lần hỏi nếu bộ manual lớn |
155
+ | B | QC điền một file checklist (`MANUAL_RUN.md`), lệnh đọc file đó rồi ghi trace | Điền offline, dễ nhiều người | Thêm một artifact phải bảo trì |
156
+
157
+ Không tự chọn — **hỏi chị QC trước khi viết lệnh này** (đã ghi trong `01-checklist.md`).
158
+
159
+ Bất kể phương án nào, hai luật giữ nguyên:
160
+ - Áp `positive_assertion_guards`: row `DRIFT`/`ORPHANED` → **không bao giờ ghi `pass`**, hạ
161
+ `not_run`.
162
+ - `qc_status = pass` phải có **bằng chứng** (ai chạy, ngày nào, ảnh/ghi chú). Không cho phép
163
+ "pass vì tôi nói vậy" — cùng tinh thần với `/qc-run-script` phải có output runner.
164
+
165
+ ## 4. Sửa file nào
166
+
167
+ ### 4.1 File lệnh
168
+
169
+ | File | Việc |
170
+ |---|---|
171
+ | `commands/qc-design-script.tmpl` | **Mới** |
172
+ | `commands/qc-run-script.tmpl` | **Mới** |
173
+ | `commands/qc-run-manualtest.tmpl` | **Mới** — không có trong đề xuất, tự viết |
174
+ | `commands/qc-run-test.tmpl` + `.md` | **Gỡ** |
175
+
176
+ Cả 3 file mới: `{{include:steps/gate.md}}` + `{{include:steps/qc-scope.md}}` + nhãn
177
+ `*Checkpoint:*`. Nguồn tham khảo: `D:\base\qcframework_proposal\command\{qc-design-script,
178
+ qc-run-script}.md` — gỡ comment provenance, thay gate cắt tay.
179
+
180
+ ### 4.2 Schema — 21 chỗ (bảng ở §2)
181
+
182
+ - `actors` (:31): 1 entry → 3 entry.
183
+ - `tsv_columns` cột 10–13: `written_by` đổi `qc-run-test` → `qc-run-script` **+**
184
+ `qc-run-manualtest`. Cột 1, 8, 9, 21 (`read_by`) → cả 3 lệnh mới, tuỳ lệnh nào thật sự đọc.
185
+ - `positive_assertion_guards` (:1769): `owner` → 2 lệnh ghi trace.
186
+ - `strict_use_check` (:1821), `queues` (:1060), `tags` (:197, :204, :480).
187
+ - 4 chỗ văn xuôi (:483, :484, :785, :802): sửa cho khớp, đừng để giải thích nói tên lệnh đã chết.
188
+
189
+ ### 4.3 Lệnh khác nhắc tên cũ — 12 file
190
+
191
+ `dev-gen-test` · `dev-run-test` · `fix-bug` · `generate-bdd` · `generate-code` · `qc-analyze` ·
192
+ `qc-design-test` · `qc-plan` · `qc-report` · `report-bug` · `validate-traces` (`.tmpl`).
193
+
194
+ ### 4.4 Step, rule, skill, module
195
+
196
+ | File | Việc |
197
+ |---|---|
198
+ | `steps/context-loader.md`, `steps/report-footer.md`, `rules/workflow.md` | Đổi tên lệnh; cập nhật bảng Phase + Next |
199
+ | ~13 file `skills/qc/**` | Đổi tên lệnh (`DOC_GAP.template.md`, `spec-issue-reporter.md`, `tc-metadata-format.md`, `qa-reviewer/**`) |
200
+ | `skills/qc/qa-runner/**` (9 file) | **GIỮ** — `/qc-run-manualtest` dùng. Chỉ sửa chỗ nhắc `/qc-run-test` |
201
+ | `modules/qc-playwright/` | Thay bằng `modules/qc-playwright-ts/` (web: TypeScript + Playwright Test) + `modules/qc-wdio-appium/` (mobile: WebdriverIO + Appium `FlutterIntegration`). Giữ `qc-playwright` deprecated 1 version |
202
+ | `bin/qc-base-map.json` | Entry cho skill mới: `qa-script-designer/**`, `qa-script-runner/**`, `qa-testdata/**`, `_shared/**` |
203
+
204
+ ### 4.5 Cấu hình & ngân sách
205
+
206
+ | File | Việc |
207
+ |---|---|
208
+ | `templates/project-context.yaml` + `path_keys` | Thêm `qc_automation_dir`, `feedback_dir` |
209
+ | `test/run.js` | Test *"tổng lệnh phải ở mức slim"*: `1200` → `1450`. **Comment nêu rõ vì sao**: thêm bộ QC 10+2, không phải vì một step lớn bị inline lại. Đo lại số thật rồi chốt |
210
+
211
+ ### 4.6 Việc dọn bắt buộc — làm kèm, xem [`01-checklist.md`](01-checklist.md)
212
+
213
+ 14 file skill còn gọi `TC_<FEATURE>.md` · 1 ref skill treo · 6 lệnh thiếu nhãn Checkpoint ·
214
+ 12 comment provenance · 12 gate cắt tay.
215
+
216
+ ### 4.7 Tài liệu
217
+
218
+ `docs/explain/19-qc-run-test.md` (tách thành 3) · `docs/04-reference/commands.md` ·
219
+ `docs/02-concepts/pipeline-steps/08-qc-automation.md` · `docs/03-guides/tester-qa.md` ·
220
+ `sdd-guide.html`.
221
+
222
+ ## 5. Kiểm thế nào để biết đã xong
223
+
224
+ ```bash
225
+ # 1. Không còn dấu vết tên cũ trong file nguồn
226
+ grep -rn "qc-run-test" commands/ steps/ rules/ skills/ bin/ modules/ templates/ | grep -v "^GAPS"
227
+ # → 0 kết quả
228
+
229
+ # 2. Bốn lệnh kiểm
230
+ node bin/build.js && node bin/self-check.js && node test/run.js && node bin/lint-trace.js
231
+
232
+ # 3. Ba lệnh mới được ship
233
+ ls core/commands/qc-design-script.md core/commands/qc-run-script.md core/commands/qc-run-manualtest.md
234
+
235
+ # 4. Ngân sách thật là bao nhiêu
236
+ node -e "const fs=require('fs'),p=require('path');let t=0;for(const f of fs.readdirSync('core/commands'))if(f.endsWith('.md'))t+=fs.statSync(p.join('core/commands',f)).size;console.log(Math.round(t/1024)+' KB')"
237
+ ```
238
+
239
+ Kiểm bằng tay trên 1 PRD thật — **phép thử quyết định là dòng cuối**:
240
+
241
+ ```bash
242
+ /qc-design-script {TICKET-ID} # cột Script file được điền; P0 có tag @smoke
243
+ /qc-review-script {TICKET-ID} # APPROVED
244
+ /qc-run-script {TICKET-ID} # ép 1 test flaky → qc_status = not_run, qc_owner = qc
245
+ /qc-run-manualtest {TICKET-ID} # ghi qc_status cho TC Automatable:N
246
+ ```
247
+
248
+ Rồi mở sổ trace: **mọi** SC phải có `qc_status ≠ not_run` (trừ SC thật sự chưa xử lý). Nếu SC
249
+ manual vẫn `not_run` thì `/qc-run-manualtest` chưa làm đúng việc — và Đợt 3 sẽ FAIL.
250
+
251
+ Thêm 2 ca âm:
252
+ - `/qc-run-script` khi `/qc-review-script` verdict `NEEDS_FIX` → phải **DỪNG**.
253
+ - Ghi `pass` trên row `DRIFT` → phải bị hạ `not_run` (cả `run-script` lẫn `run-manualtest`).
254
+
255
+ ## 6. Nếu bỏ qua thì hỏng gì
256
+
257
+ **Bỏ cả bước:** pipeline giữ nguyên 6 trạm, `/qc-run-test` vẫn gánh 4 việc, và Đợt 3 + Đợt 4
258
+ không có nền để dựng (`/qc-report` cần `Automatable` + kết quả theo TC; `/qc-smoke-test` cần tag
259
+ `@smoke` do `design-script` gắn).
260
+
261
+ **Làm bước này mà bỏ `/qc-run-manualtest`:** tệ hơn cả bỏ cả bước. Ta sẽ có pipeline mới đầy đủ,
262
+ `/qc-report` với 8 ngưỡng và verdict — và verdict đó **luôn FAIL** với mọi PRD có test tay. Đội
263
+ QC sẽ làm điều hợp lý duy nhất còn lại: hạ `coverage_min` xuống 0 và `not_run_p0_max` lên vô
264
+ cùng, để verdict xanh. Lúc đó cả Đợt 3 thành trang trí.
265
+
266
+ **Chia nhỏ commit:** build đỏ ở commit giữa (§3.1). Nếu ai đó merge commit giữa vào `main` thì
267
+ `npm run build` của mọi người cùng đỏ, và không publish được.
@@ -0,0 +1,198 @@
1
+ ---
2
+ buoc: Đợt 2 — Bước 3
3
+ title: Thêm /qc-automation-assess + cột Script file
4
+ phu_thuoc: d2-b2
5
+ trang_thai: chưa làm
6
+ ---
7
+
8
+ # Đợt 2 · Bước 3 — Quyết định "cái nào máy chạy, cái nào phải tay" thành một bước có hồ sơ
9
+
10
+ ← [`01-checklist.md`](01-checklist.md) · [`02-lo-trinh.md`](02-lo-trinh.md)
11
+
12
+ ## 1. Vì sao
13
+
14
+ ### 1.1 Framework hiện ngầm định mọi test case đều automate được
15
+
16
+ `/qc-run-test` nhận `.Test.md` rồi sinh script cho **tất cả**. Nhưng thực tế luôn có TC không nên
17
+ hoặc không thể automate:
18
+
19
+ | TC | Vì sao không automate |
20
+ |---|---|
21
+ | Đăng nhập bằng OTP gửi SMS | Cần mã do người/bên thứ ba sinh ra |
22
+ | Xác minh captcha | Cùng lý do |
23
+ | In hoá đơn ra máy in thật | Thiết bị vật lý |
24
+ | Màn hình đang redesign hàng tuần | Chi phí bảo trì script > lợi ích |
25
+ | Test chạy 1 lần trước khi tính năng bị bỏ | Effort > ROI |
26
+
27
+ Hiện chúng vẫn bị sinh script, rồi `pytest.skip("lý do")`. Ba hệ quả:
28
+
29
+ 1. **Quyết định không được ghi lại.** Sáu tháng sau không ai biết vì sao TC đó skip — là do
30
+ không automate được, hay do quên?
31
+ 2. **Không có số liệu.** Câu "automation phủ bao nhiêu %?" không trả lời được, vì mẫu số lẫn cả
32
+ TC không bao giờ định automate.
33
+ 3. **TC không automate được biến mất khỏi tầm nhìn.** Nó nằm trong file test case, có dòng
34
+ `skip`, và không ai chạy tay nó cả. Đây là nửa còn lại của lỗ hổng mà
35
+ [`exec-d2-b2`](exec-d2-b2-tach-qc-run-test-atomic.md) bịt bằng `/qc-run-manualtest` — bước
36
+ này là nửa *"biết TC nào cần chạy tay"*.
37
+
38
+ ### 1.2 Không có đường từ test case → file code
39
+
40
+ Hiện muốn biết TC nào được test bởi file nào thì phải `grep` tag `@trace.verifies` trong code.
41
+ Ngược lại — *"file `login.spec.ts` phục vụ những TC nào"* — phải đọc cả file.
42
+
43
+ `/qc-run-script` cần biết **chạy file nào** cho UC này. Không có chỉ mục thì nó phải tự suy
44
+ đường dẫn từ quy ước đặt tên — và suy sai thì chạy sai bộ test, hoặc không chạy gì mà vẫn báo
45
+ xanh.
46
+
47
+ ## 2. Tình trạng hiện tại
48
+
49
+ **Không có lệnh nào cho việc này.** Trong 33 lệnh hiện tại không có bước đánh giá khả năng
50
+ automate. `/qc-design-test` viết test case rồi chuyển thẳng sang `/qc-review` → `/qc-run-test`.
51
+
52
+ **`.Test.md` không có field nào ghi quyết định automate.** Kiểm
53
+ `skills/qc/qa-designer/shared/tc-metadata-format.md` — có `Priority`, có `@trace.verifies`, có
54
+ `Test Data`, **không có** `Automatable`.
55
+
56
+ **Không có chỉ mục ngược TC → file code.** `bin/lint-trace.js` có rule `T14` đi từ code → sổ
57
+ trace (`@trace.implements`), nhưng đó là code sản phẩm, không phải code test.
58
+
59
+ ## 3. Sẽ đổi thành gì
60
+
61
+ ### 3.1 Lệnh mới `/qc-automation-assess`
62
+
63
+ Chạy **sau** `/qc-review-testcase` (chỉ nhận TC verdict `APPROVED`) và **trước**
64
+ `/qc-design-script`. Ghi `AUTOMATION_ASSESSMENT.md` vào `qc_artifact_dir` (cấp PRD, cùng chỗ
65
+ `TEST_PLAN.md`):
66
+
67
+ ```markdown
68
+ # Automation Assessment — {TICKET-ID} ({active_platform})
69
+
70
+ | TC ID | UC | Automatable | Lý do (nếu N) | Trace SC | Script file | Ghi chú |
71
+ |---|---|:---:|---|---|---|---|
72
+ | TC_LOGIN_001 | UC1 | Y | — | UC1-SC1 | — *(chưa qua design-script)* | |
73
+ | TC_LOGIN_004 | UC1 | N | Cần OTP/captcha thủ công | UC1-SC4 | — *(không automate)* | Giữ bộ manual |
74
+
75
+ **%Automated/Total: {automatable}/{total} = {pct}%**
76
+ ```
77
+
78
+ ### 3.2 Nhãn lý do — danh sách cố định, mở rộng được
79
+
80
+ | Nhãn | Khi dùng |
81
+ |---|---|
82
+ | `Cần OTP/captcha thủ công` | Bước bắt buộc nhập mã do người/bên thứ ba sinh |
83
+ | `Phụ thuộc hệ thống ngoài` | App khác, thiết bị vật lý, email thật |
84
+ | `UI không ổn định` | Màn đang redesign/A-B test, bảo trì script > lợi ích |
85
+ | `Effort > ROI` | Tần suất chạy thấp, hoặc chi phí viết/bảo trì vượt giá trị |
86
+ | `Thiếu test-id contract` | Element không có test-id ổn định và dev chưa cam kết thêm |
87
+
88
+ Không khớp nhãn nào → **tạo nhãn mới** mô tả đúng lý do (không ép vào nhãn có sẵn), rồi ghi nhãn
89
+ mới đó trong report để bổ sung vào danh sách lần sau.
90
+
91
+ Vì sao chuẩn hoá nhãn: để đếm được. *"3 TC không automate vì thiếu test-id"* là một tín hiệu
92
+ hành động được (đi đàm phán với dev); *"3 TC vì lý do kỹ thuật"* thì không.
93
+
94
+ Riêng nhãn `Thiếu test-id contract` nối trực tiếp với Đợt 0: nếu Đợt 0 làm đúng thì nhãn này
95
+ phải **giảm dần** theo thời gian.
96
+
97
+ ### 3.3 Cột `Script file` — chỉ mục ngược tường minh
98
+
99
+ ```
100
+ Khởi tạo ở bước này → "—"
101
+ /qc-design-script điền → qc-automation/web/tests/academic/FT-101-login/login.spec.ts
102
+ /qc-run-script ĐỌC cột này → biết chạy file nào, KHÔNG tự suy path
103
+ ```
104
+
105
+ Đây là điều kiện để `/qc-run-script` không đoán. Đề xuất đã có ý này; giữ nguyên.
106
+
107
+ ### 3.4 Cờ re-assessment tự động theo `DRIFT`
108
+
109
+ Trước khi đánh giá TC mới, quét cột `status` trong sổ trace. Với TC đã có dòng trong
110
+ `AUTOMATION_ASSESSMENT.md` từ lần trước mà scenario nó verify đang `DRIFT` (spec/BDD đã đổi):
111
+
112
+ - Gắn cờ `🔄 Re-assess` — quyết định `Y/N` cũ **không còn đáng tin**.
113
+ - Đánh giá lại **ngay trong lượt này**, không cần lịch định kỳ, không cần ai nhắc.
114
+ - Nếu kết quả đổi `Y → N` (đã có script, giờ không nên automate nữa): **giữ** path cũ trong cột
115
+ `Script file` + ghi chú `⚠️ Script đã lỗi thời — cân nhắc gỡ ở lần /qc-design-script kế tiếp`.
116
+ **Không tự xoá file** — để người quyết định.
117
+ - Nếu `N → Y`: cột vẫn `—`, chờ `/qc-design-script`.
118
+
119
+ ### 3.5 TC `Automatable: N` không mất đi
120
+
121
+ Ba điều phải đúng:
122
+
123
+ 1. **Không xoá khỏi `.Test.md`** — bộ test tay không đổi.
124
+ 2. **Là đầu vào của `/qc-run-manualtest`** (d2-b2) — lệnh đó lọc `Automatable: N` từ file này để
125
+ biết phải chạy tay những gì. Đây là mắt xích khiến execution coverage của Đợt 3 đạt được.
126
+ 3. **TC `Priority: P0` mà `Automatable: N` → cảnh báo riêng.** Tính năng lõi không có smoke test
127
+ tự động là tín hiệu đáng chú ý: cân nhắc `IMPROVE-xxx` để gỡ rào cản thay vì chấp nhận `N`
128
+ luôn.
129
+
130
+ ### 3.6 Chốt một chỗ còn nhoè về phạm vi
131
+
132
+ `/qc-automation-assess` chạy theo **TICKET-ID** (cả PRD), còn `/qc-review-testcase` chạy theo
133
+ **UC-ID**. PRD 3 UC mà chỉ UC1 `APPROVED` thì sao? Chốt hành vi:
134
+
135
+ - Đánh giá TC của UC đã `APPROVED`.
136
+ - TC của UC còn `Draft`/`NEEDS_FIX` → **loại khỏi lượt**, và **liệt kê ra trong report** kèm
137
+ trạng thái thật.
138
+ - `%Automated/Total` tính trên mẫu số **chỉ gồm TC đã đánh giá**, và in kèm số TC bị loại — để
139
+ không ai đọc "100%" mà tưởng đã phủ cả PRD.
140
+
141
+ Nguyên tắc: *"chưa xét" khác "đã xét, sạch"* — cùng tinh thần bảng phạm vi của
142
+ `steps/qc-scope.md`.
143
+
144
+ ## 4. Sửa file nào
145
+
146
+ | File | Việc |
147
+ |---|---|
148
+ | `commands/qc-automation-assess.tmpl` | **Mới** — `{{include:steps/gate.md}}` + `{{include:steps/qc-scope.md}}` + nhãn `*Checkpoint:*` |
149
+ | `skills/qc/qa-automation-assess/matrix.md` | **Mới** — tiêu chí đánh giá, danh sách nhãn, công thức ROI, khuôn bảng |
150
+ | `commands/qc-design-script.tmpl` | Đọc `AUTOMATION_ASSESSMENT.md`, lọc `Automatable: Y`; điền cột `Script file` sau khi sinh |
151
+ | `commands/qc-run-script.tmpl` | Đọc cột `Script file` để biết chạy file nào |
152
+ | `commands/qc-run-manualtest.tmpl` | Đọc `Automatable: N` để biết chạy tay những gì |
153
+ | `skills/qc/qa-designer/shared/tc-metadata-format.md` | Cân nhắc thêm ghi chú: quyết định `Automatable` **không** nằm trong `.Test.md`, nó ở `AUTOMATION_ASSESSMENT.md` (tránh hai chỗ ghi cùng một quyết định) |
154
+ | `steps/report-footer.md` | Bảng Phase + Next |
155
+ | `bin/qc-base-map.json` | Entry cho `qa-automation-assess/matrix.md` |
156
+ | `docs/04-reference/commands.md`, `docs/02-concepts/pipeline-steps/08-qc-automation.md` | Thêm lệnh mới |
157
+
158
+ Nguồn: `D:\base\qcframework_proposal\command\qc-automation-assess.md` +
159
+ `skills\qc\qa-automation-assess\matrix.md`. Gỡ comment provenance, thay gate cắt tay, và **sửa
160
+ `matrix.md` đang gọi `TC_<FEATURE>.md`** → `.Test.md` (nằm trong 14 file cần dọn).
161
+
162
+ ⚠️ R16(d): tạo `skills/qc/qa-automation-assess/matrix.md` **trước hoặc cùng lúc** với việc lệnh
163
+ tham chiếu tới nó, không thì `self-check` đỏ.
164
+
165
+ ## 5. Kiểm thế nào để biết đã xong
166
+
167
+ ```bash
168
+ node bin/build.js && node bin/self-check.js && node test/run.js
169
+ ls core/commands/qc-automation-assess.md
170
+ grep -n "TC_<FEATURE>" skills/qc/qa-automation-assess/matrix.md # → 0 kết quả
171
+ ```
172
+
173
+ Kiểm bằng tay trên PRD có **cả hai loại** TC:
174
+
175
+ 1. `/qc-automation-assess {TICKET-ID}` → `AUTOMATION_ASSESSMENT.md` có đủ TC, mỗi TC có `Y/N`,
176
+ `N` phải kèm nhãn từ danh sách; `%Automated` là **phép chia thật** trên số dòng bảng.
177
+ 2. Cột `Script file` phải là `—` ở lượt này (script chưa tồn tại).
178
+ 3. `/qc-design-script {TICKET-ID}` → chỉ sinh script cho `Y`; cột `Script file` được điền.
179
+ 4. `/qc-run-script {TICKET-ID}` → chạy đúng file trong cột đó, **không** đoán path.
180
+ 5. **Ca DRIFT:** đổi một scenario trong `.feature` để row trace thành `DRIFT`, chạy lại lệnh →
181
+ TC tương ứng phải có cờ `🔄 Re-assess` và được đánh giá lại.
182
+ 6. **Ca phạm vi:** PRD 2 UC, để 1 UC `Draft` → report phải liệt kê TC bị loại, và `%Automated`
183
+ phải in kèm số TC bị loại.
184
+ 7. **Ca P0+N:** đặt một TC `P0` thành `Automatable: N` → phải có cảnh báo riêng.
185
+
186
+ ## 6. Nếu bỏ qua thì hỏng gì
187
+
188
+ Ba mắt xích đứt cùng lúc:
189
+
190
+ 1. **`/qc-design-script` không biết sinh script cho TC nào** → quay lại ngầm định "tất cả", và
191
+ TC không automate được lại bị `skip` rồi biến mất.
192
+ 2. **`/qc-run-manualtest` không biết chạy tay TC nào** → lệnh vừa thêm ở d2-b2 không có đầu vào
193
+ → lỗ hổng execution coverage của Đợt 3 **không được bịt**, dù đã có lệnh.
194
+ 3. **`/qc-run-script` phải tự suy đường dẫn file test** → suy sai thì chạy sai bộ test hoặc
195
+ không chạy gì mà vẫn báo xanh. Đây là kiểu hỏng im lặng tệ nhất: báo cáo xanh trên một lần
196
+ chạy không tồn tại.
197
+
198
+ Và mất luôn chỉ số `%Automated/Total` — con số đầu tiên mà Lead/PM sẽ hỏi khi thấy pipeline mới.