@educa-corp/sdd-framework 0.9.5 → 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 (55) hide show
  1. package/bin/build.js +11 -1
  2. package/bin/lint-trace.js +397 -28
  3. package/bin/self-check.js +183 -12
  4. package/bin/trace-schema.json +2656 -1981
  5. package/core/FRAMEWORK_VERSION +1 -1
  6. package/core/commands/dev-gen-test.md +62 -0
  7. package/core/commands/generate-code.md +1 -1
  8. package/core/commands/generate-tech-docs.md +3 -3
  9. package/core/commands/map-testids.md +88 -11
  10. package/core/commands/qc-analyze.md +509 -425
  11. package/core/commands/qc-design-test.md +475 -247
  12. package/core/commands/qc-plan.md +134 -93
  13. package/core/commands/qc-review.md +216 -131
  14. package/core/commands/qc-run-test.md +346 -231
  15. package/core/commands/validate-traces.md +17 -2
  16. package/core/rules/workflow.md +40 -0
  17. package/core/skills/qc/qa-analyst/DOC_GAP.template.md +9 -1
  18. package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +33 -5
  19. package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +24 -0
  20. package/core/skills/qc/qa-planner/test-plan.md +7 -0
  21. package/core/skills/qc/qa-runner/functional/gui-feature.md +1 -1
  22. package/core/skills/qc/qa-runner/functional/gui-screen.md +1 -1
  23. package/core/steps/qc-scope.md +67 -11
  24. package/core/steps/qc-stamp.md +142 -0
  25. package/core/steps/report-footer.md +13 -5
  26. package/core/templates/tech-design.template.md +3 -3
  27. package/docs/01-getting-started/quickstart.md +4 -3
  28. package/docs/02-concepts/architecture.md +14 -0
  29. package/docs/02-concepts/glossary.md +8 -0
  30. package/docs/02-concepts/overview.md +3 -2
  31. package/docs/02-concepts/pipeline-steps/04-bdd.md +1 -1
  32. package/docs/02-concepts/pipeline-steps/05-tech-docs.md +21 -5
  33. package/docs/02-concepts/pipeline-steps/06-code.md +12 -2
  34. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +60 -12
  35. package/docs/02-concepts/pipeline-steps/README.md +4 -3
  36. package/docs/02-concepts/traceability.md +2 -2
  37. package/docs/03-guides/architect.md +2 -2
  38. package/docs/03-guides/developer.md +5 -2
  39. package/docs/03-guides/tester-qa.md +17 -5
  40. package/docs/04-reference/commands.md +6 -3
  41. package/docs/04-reference/trace-schema.md +1 -1
  42. package/docs/explain/07-generate-tech-docs.md +5 -3
  43. package/docs/explain/08-review-tech-docs.md +15 -3
  44. package/docs/explain/09-generate-code.md +30 -4
  45. package/docs/explain/10-review-code.md +1 -1
  46. package/docs/explain/11-map-testids.md +72 -70
  47. package/docs/explain/12-dev-gen-test.md +1 -1
  48. package/docs/explain/15-qc-analyze.md +14 -2
  49. package/docs/explain/16-qc-plan.md +5 -1
  50. package/docs/explain/17-qc-design-test.md +26 -3
  51. package/docs/explain/18-qc-review.md +6 -2
  52. package/docs/explain/19-qc-run-test.md +29 -6
  53. package/docs/explain/20-qc-report.md +5 -2
  54. package/docs/explain/README.md +4 -1
  55. package/package.json +1 -1
@@ -1,14 +1,14 @@
1
- ---
2
- version: 1.0
3
- updated: 2026-06-11
4
- ported_from: ai-automation-qc-base
5
- ---
6
-
7
- # /qc-review — QC Review Gate (test case & script)
8
-
9
- > Stage 4 của QC automation pipeline native (qc-analyze → qc-plan → qc-design-test → qc-review → qc-run-test → qc-report). Port từ qa-reviewer của team QC. Một gate hai chiều: review test case (sau qc-design-test) VÀ script (sau qc-run-test).
10
-
11
- ## Gate
1
+ ---
2
+ version: 1.0
3
+ updated: 2026-06-11
4
+ ported_from: ai-automation-qc-base
5
+ ---
6
+
7
+ # /qc-review — QC Review Gate (test case & script)
8
+
9
+ > Stage 4 của QC automation pipeline native (qc-analyze → qc-plan → qc-design-test → qc-review → qc-run-test → qc-report). Port từ qa-reviewer của team QC. Một gate hai chiều: review test case (sau qc-design-test) VÀ script (sau qc-run-test).
10
+
11
+ ## Gate
12
12
  # Gate — Quy trình vào chuẩn cho mọi lệnh
13
13
 
14
14
  Mọi lệnh PHẢI chạy gate này trước khi thực thi phần logic riêng của nó.
@@ -160,134 +160,219 @@ Mỗi dòng ⚠️/🔴 phải ứng với một trạng thái **context-loader
160
160
  - "N" → dừng, hỏi người dùng muốn thay đổi gì.
161
161
  - Có `--yes` và mức *chặn thường* → coi như "Y", **nhưng vẫn IN khối CHECKPOINT** nếu có cờ
162
162
  🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
163
-
164
-
165
- *Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID (`active_platform` + `qc_artifact_dir` do §Phạm vi QC phân giải). Phát hiện review mode từ `$ARGUMENTS`/context: review test-case `.Test.md` (sau design) hoặc review Python script (sau run). Đọc artifact từ `{qc_artifact_dir}` và source test/page-object đã sinh.*
166
-
167
- ## Context
163
+
164
+
165
+ *Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID (`active_platform` + `qc_artifact_dir` do §Phạm vi QC phân giải). Phát hiện review mode từ `$ARGUMENTS`/context: review test-case `.Test.md` (sau design) hoặc review Python script (sau run). Đọc artifact từ `{qc_artifact_dir}` và source test/page-object đã sinh.*
166
+
167
+ ## Context
168
168
  **BẮT BUỘC — đọc `.agent/steps/context-loader.md` và thực thi TOÀN BỘ quy trình trong đó**,
169
169
  rồi mới tiếp tục phần bên dưới.
170
170
 
171
171
  Bỏ qua bước này thì `{paths.*}`, `{tech_stack.*}`, `{conventions.*}`, guardrail từ
172
172
  `project-lessons`, và routing service (chế độ umbrella) đều **chưa được phân giải** — mọi
173
- placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
174
-
175
- ## Phạm vi QC
176
-
173
+ placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
174
+
175
+ ## Phạm vi QC
176
+
177
177
  **BẮT BUỘC — đọc `.agent/steps/qc-scope.md` và thực thi TOÀN BỘ quy trình trong đó**,
178
178
  rồi mới tiếp tục phần bên dưới.
179
179
 
180
180
  Nó chốt bốn thứ mà mọi trạm QC đều cần: `TICKET-ID` · `active_platform` ·
181
- `qc_artifact_dir` · `uc_list` (kèm trạng thái BDD từng UC, và cờ `--include-draft`).
181
+ `qc_artifact_dir` · `uc_list` (kèm trạng thái BDD từng UC, và cờ `--force`).
182
182
  Bỏ qua thì artifact QC ghi vào **sai thư mục** và `qc_status` ghi vào **sai sổ trace** —
183
- cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắt được.
184
-
185
- > **Trạm này vẫn gọi theo TỪNG UC** *(B11)* — thiết kế và chạy test **thật sự** làm tăng dần
186
- > theo UC, nên giữ khả năng làm UC1 khi UC3 chưa xong là đúng. Chỉ **chỗ đọc/ghi** đổi: mọi
187
- > artifact nằm chung ở `{qc_artifact_dir}` cấp PRD, không còn một thư mục mỗi UC.
188
- >
189
- > Nên `DOC_GAP.md` / `TEST_PLAN.md` đọc được đây phủ **cả PRD**: **lọc theo cột `UC`** để lấy
190
- > phần của UC đang làm. Đừng coi toàn bộ bảng gap là của UC này — sẽ chặn oan.
191
-
192
- ---
193
-
194
-
195
- ---
196
-
197
- ## Role
198
-
199
- Bạn **QC Reviewer** gate review dùng chung, chạy hai lần trong pipeline:
200
- 1. **Sau qc-design-test** → review test-case `.Test.md` (coverage, độ rõ ràng, trace).
201
- 2. **Sau qc-run-test** review Python script / Page Object đã sinh.
202
-
203
- Phát hiện mode: nếu artifact target là `.Test.md` → review test-case; nếu file Python test/PO
204
- tồn tại cho UC và mới hơn → review script. Nếu mơ hồ, hỏi.
205
-
206
- ## Skills (`{paths.qc_skills_dir}/qa-reviewer/`)
207
-
208
- **Nạp trước — nhưng đúng vai:**
209
-
210
- | File | Vai nào | Cho gì |
211
- |---|---|---|
212
- | `shared/read-doc-gap-inputs.md` | **cả hai** | Nạp **đủ** mọi tài liệu nguồn theo bảng *Tài liệu đầu vào đã đọc* của `DOC_GAP.md` soát thì kết luận "0 lỗi" là vô nghĩa |
213
- | `shared/review-file-template.md` | **cả hai** | Khuôn file kết quả · thang điểm `XX/100` · luật ghi file · nguyên tắc *mặc định hoài nghi* |
214
- | ↳ §*Kiểm tra cấu trúc TC* của file đó | **chỉ vai 1** | Tầng kiểm các luật của trạm 3: ATOMIC 1-bullet · không ký tự `\|` · cụm từ mơ hồ · teardown đúng chỗ · marker ≠ oracle |
215
- | `shared/review-check-groups.md` | **chỉ vai 1** | **7 nhóm kiểm tra** chạy tuần tự · registry 46 nhãn lỗi · **7 mẫu-hay-thiếu** của Nhóm 6 · nền tảng ISTQB · anti-pattern |
216
-
217
- > ⚠️ **Vai 2 (soát code) KHÔNG nạp 7 nhóm kiểm tra.** Chúng kiểm **cấu trúc file test case** —
218
- > áp vào file Python là bảo reviewer đi tìm `#### Expected Result` trong một Page Object, rồi
219
- > 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`.
220
-
221
- **Rồi chọn theo vai + tầng, nạp MỘT file:**
222
- - Soát test-case: `test-case/{functional,e2e,integration,non-functional,exploratory}.md`
223
- - Soát script: `script/{functional,e2e,integration,non-functional,exploratory}.md`
224
-
225
- ## Review focus
226
-
227
- - **Test-case:** mọi `{UC-ID}-SC{N}` đã phủ? happy + negative + boundary? expected cụ thể? trace (`BR-xx` + `@trace.verifies` SC) mặt? không TC orphan?
228
- - **Script:** khớp `.Test.md` 1-1? Page Object 3 lớp + BasePage gọn? `expect()` không phải bare assert? không hard-code URL/cred/timeout, không `time.sleep`, không Allure? selector theo priority (data-testid→role→…)? 100% TC đã script (không còn Draft)?
229
-
230
- Sinh findings (mức độ + vị trí + cách sửa), chấm điểm, ra verdict.
231
-
232
- **KHÔNG tự sửa** file TC hay code. Chỉ nhận xét và chấm điểm — người sửa là `/qc-design-test`
233
- (vai 1) hoặc `/qc-run-test` (vai 2). *Reviewer tự sửa rồi tự duyệt là bỏ mất cái cổng.*
234
-
235
- ## Output
236
-
237
- Ghi vào **`{qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md`** — đứng **cạnh** file TC vừa soát:
238
-
239
- ```
240
- {qc_artifact_dir}test-cases/
241
- ├── TC_<FEATURE>.Test.md
242
- ├── REVIEW_<FEATURE>.md ← soát file trên
243
- ├── TC_<FEATURE>_API.Test.md
244
- └── REVIEW_<FEATURE>_API.md ← soát file trên
245
- ```
246
-
247
- ⚠️ **Tên file review KHÔNG đuôi `.Test.md`.** Đuôi đó là của file test case; gắn vào file
248
- review sẽ làm `/qc-run-test` nhặt lên như một file test case rồi cố sinh script từ một bảng điểm.
249
-
250
- Khuôn đầy đủ + quy tắc ghi: `shared/review-file-template.md`. Ba điều bắt buộc:
251
-
252
- - **Điểm `XX/100`** trừ mỗi `FAIL`, mỗi `WARN`. Verdict **suy ra được**:
253
- `≥80` không còn `FAIL` chặn `APPROVED`; ngược lại `NEEDS_FIX`.
254
- - **Bảng Tổng quan THÊM một hàng mỗi vòng**, không ghi đè — đó là cách duy nhất thấy được điểm
255
- có tăng không. Các bảng chi tiết thì ghi đè phần của tầng mình.
256
- - **Hai vai ghi vào CÙNG một file**, phân biệt bằng cột `Tầng`. Chúng cách nhau một trạm, nên
257
- hàng của vai sau **không được ghi đè** hàng của vai trước.
258
-
259
- > **Vì sao cổng này phải ghi ra file** *(B13)*. Trước đây lệnh chỉ nói *"sinh findings"* — không
260
- > nói ghi đâu, dạng gì, điểm `A/B/C/D` **không có luật chấm**. Hệ quả: hai người soát ra
261
- > hai kết quả, và **vòng 2 không so được với vòng 1** — tức không ai biết sửa xong có tốt lên
262
- > không. Một cổng không để lại dấu vết đo được thì không phải cổng, nó là một lượt đọc.
263
-
264
- ## Self-Review *(trước khi in Report)*
265
-
266
- Theo 3 nhóm ở `{paths.qc_skills_dir}/_shared/self-review-principles.md` — **không chép lại ở đây**.
267
-
268
- - **Bịa:** mỗi finding trỏ được về **dòng cụ thể** trong artifact đang soát không phải nhận xét
269
- chung chung? Và **cấm dùng chính field `quote` của finding làm bằng chứng cho nó** — mở lại file
270
- đọc lại đoạn đó.
271
- - **Nhảy bước:** đã đi hết bộ tiêu chí của **đúng vai** (test-case hay script), không trộn hai
272
- bộ? Verdict `APPROVED` phát ra **sau** khi soát đủ, không phải vì "trông ổn"?
273
- - **Số liệu:** số finding theo mức (critical/major/minor) = đếm thật trên file findings vừa ghi?
274
-
275
- > **Verdict của lệnh này cổng cho trạm sau.** Một `APPROVED` phát ra sớm không chỉ sai ở đây —
276
- > mở đường cho `/qc-run-test` sinh script từ một bộ TC chưa đạt. Đây chỗ self-review đắt
277
- > nhất nếu bỏ qua.
278
-
279
- ## Report
280
-
183
+ cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắt được.
184
+
185
+ ---
186
+
187
+ ## Stamp phiên bản nguồn
188
+
189
+ **BẮT BUỘC đọc `.agent/steps/qc-stamp.md` thực thi phần áp cho lệnh này**,
190
+ rồi mới tiếp tục phần bên dưới.
191
+
192
+ Nó có **hai vế**: §1 **ghi** khối `Nguồn & phiên bản` vào artifact lệnh này sinh ra ·
193
+ §2 **so** stamp của artifact lệnh này ĐỌC với version hiện tại của spec.
194
+ Bỏ vế ghi thì trạm sau không có gì để so; bỏ vế so thì stamp thành một con số không ai
195
+ đọc — và một bộ TC lỗi thời sẽ chạy xanh rồi ghi `pass` **hợp lệ theo mọi phép kiểm**.
196
+
197
+ > **Trạm này vẫn gọi theo TỪNG UC** *(B11)* — thiết kế và chạy test **thật sự** làm tăng dần
198
+ > theo UC, nên giữ khả năng làm UC1 khi UC3 chưa xong là đúng. Chỉ **chỗ đọc/ghi** đổi: mọi
199
+ > artifact nằm chung `{qc_artifact_dir}` cấp PRD, không còn một thư mục mỗi UC.
200
+ >
201
+ > Nên `DOC_GAP.md` / `TEST_PLAN.md` đọc được đây phủ **cả PRD**: **lọc theo cột `UC`** để lấy
202
+ > phần của UC đang làm. Đừng coi toàn bộ bảng gap là của UC này — sẽ chặn oan.
203
+
204
+ ---
205
+
206
+
207
+ ---
208
+
209
+ ## Role
210
+
211
+ Bạn là **QC Reviewer** — gate review dùng chung, chạy hai lần trong pipeline:
212
+ 1. **Sau qc-design-test** review test-case `.Test.md` (coverage, độ ràng, trace).
213
+ 2. **Sau qc-run-test** review Python script / Page Object đã sinh.
214
+
215
+ Phát hiện mode: nếu artifact target `.Test.md` review test-case; nếu file Python test/PO
216
+ tồn tại cho UC và mới hơn → review script. Nếu mơ hồ, hỏi.
217
+
218
+ ## Skills (`{paths.qc_skills_dir}/qa-reviewer/`)
219
+
220
+ **Nạp trước — nhưng đúng vai:**
221
+
222
+ | File | Vai nào | Cho gì |
223
+ |---|---|---|
224
+ | `shared/read-doc-gap-inputs.md` | **cả hai** | Nạp **đủ** mọi tài liệu nguồn theo bảng *Tài liệu đầu vào đã đọc* của `DOC_GAP.md` — soát mù thì kết luận "0 lỗi" là vô nghĩa |
225
+ | `shared/review-file-template.md` | **cả hai** | Khuôn file kết quả · thang điểm `XX/100` · luật ghi file · nguyên tắc *mặc định hoài nghi* |
226
+ | ↳ §*Kiểm tra cấu trúc TC* của file đó | **chỉ vai 1** | Tầng kiểm các luật của trạm 3: ATOMIC 1-bullet · không ký tự `\|` · cụm từ mơ hồ · teardown đúng chỗ · marker ≠ oracle |
227
+ | `shared/review-check-groups.md` | **chỉ vai 1** | **7 nhóm kiểm tra** chạy tuần tự · registry 46 nhãn lỗi · **7 mẫu-hay-thiếu** của Nhóm 6 · nền tảng ISTQB · anti-pattern |
228
+
229
+ > ⚠️ **Vai 2 (soát code) KHÔNG nạp 7 nhóm kiểm tra.** Chúng kiểm **cấu trúc file test case** —
230
+ > áp vào file Python bảo reviewer đi tìm `#### Expected Result` trong một Page Object, rồi
231
+ > 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`.
232
+
233
+ **Rồi chọn theo vai + tầng, nạp MỘT file:**
234
+ - Soát test-case: `test-case/{functional,e2e,integration,non-functional,exploratory}.md`
235
+ - Soát script: `script/{functional,e2e,integration,non-functional,exploratory}.md`
236
+
237
+ ---
238
+
239
+ ## Guard — hợp đồng test-id, chân thứ tư *(phép so GIÁ TRỊ, một chiều)*
240
+
241
+ `bin/trace-schema.json` canh **ba** chân của hợp đồng test-id: §4.5.6 ↔ `.feature` (**T15**) ·
242
+ header `@trace.testid_attr` (**T16**) · ↔ code (**T17/T18**). Chân thứ tư — §4.5.6 ↔ `*.Test.md`
243
+ **không máy nào canh**, và nó là chân duy nhất mà giá trị id bị **chép cứng vào một artifact bền**:
244
+
245
+ ```
246
+ generate-code → bake vào code → T17/T18 canh
247
+ qc-run-test → dựng locator LÚC CHẠY → đọc bảng tươi, tự cứu
248
+ qc-design-test chép vào .Test.md → KHÔNG AI CANH ← chỗ này
249
+ ```
250
+
251
+ **Phạm vi — đọc trước khi làm gì.** Không có block §4.5 client trong tech-doc (dự án backend-only,
252
+ hoặc chưa từng chạy `/map-testids`) **im lặng hoàn toàn**, không kiểm gì. Cùng điều khoản phạm vi
253
+ với `testid_contract`: *"hai rule nói 'chỗ nào đã hứa thì phải giữ', KHÔNG nói 'mọi chỗ đều phải có
254
+ hợp đồng'"*.
255
+
256
+ **Phép so MỘT chiều:**
257
+
258
+ 1. Gom mọi test-id được nhắc trong các `*.Test.md` của UC này.
259
+ 2. Gom id §4.5.6 (block `active_platform`), **lọc theo cột "Serves SC"** khớp SC của UC này.
260
+ 3. `TC bảng` = id TC nhắc hợp đồng không có ⚠️.
261
+
262
+ | Kết quả | Làm |
263
+ |---|---|
264
+ | Rỗng | **im lặng, đi tiếp** |
265
+ | Có id lạ | `⚠️ Hợp đồng test-id: {k} id trong .Test.md không có ở §4.5.6: {danh sách}`<br/>kèm: `Chạy /map-testids {UC-ID} (đưa vào hợp đồng) hoặc /qc-design-test {UC-ID} (sửa TC theo hợp đồng).` |
266
+
267
+ **Chiều ngược KHÔNG kiểm.** §4.5.6 có id mà không TC nào nhắc là **bình thường** — không phải element
268
+ nào cũng cần một bước TC. Kiểm chiều đó **ồn**, đúng bất đối xứng T17/T18 đã chọn.
269
+
270
+ **Mức `warn`, không chặn.** Id sai làm test **ĐỎ**, không làm test **xanh giả** — nên nó **không**
271
+ thuộc lớp *"báo cáo sai"* không đi cùng đường với `steps/qc-stamp.md` §2 (chặn `pass`). Chặn đây
272
+ chặn nhầm loại.
273
+
274
+ > **Vì sao vẫn đáng cảnh báo dù test sẽ tự đỏ.** Vì nó đỏ **đội lốt thứ khác**. `testid_contract` ghi
275
+ > đúng chữ: *"test đỏ 'element not found' **trông y hệt bug sản phẩm**"* nên `/qc-report` phân loại
276
+ > *product-gap* rồi in một `/report-bug` sẵn-chạy, một lỗi **hợp đồng nội bộ** đi ra khỏi đội QC
277
+ > thành phiếu lỗi gửi PO. Dòng ⚠️ này là chỗ duy nhất chặn được chuyến đi đó.
278
+
279
+ ## Review focus
280
+
281
+ - **Test-case:** mọi `{UC-ID}-SC{N}` đã phủ? happy + negative + boundary? expected cụ thể? trace (`BR-xx` + `@trace.verifies` SC) có mặt? không có TC orphan?
282
+ - **`🚫 Block` còn hiệu lực không?** Mỗi TC mang `🚫 Block: [GAP-UC{N}-{nnn}]` → mở `../DOC_GAP.md`,
283
+ đọc `Trạng thái` của hàng gap đó. **Gap đã `Answered` mà TC vẫn mang dấu ⇒ FINDING.**
284
+
285
+ > **Vì sao là finding chứ không phải chuyện nhỏ** *(G66)*. Một TC mang `🚫 Block` là một TC có
286
+ > `Expected Result` dựa trên **giả định chưa ai xác nhận**. Khi gap được trả lời, quy trình
287
+ > `tc-metadata-format.md` §*Quy trình khi gap được giải quyết* đòi **cập nhật lại Expected Result**
288
+ > — giả định có thể đã sai. Bỏ qua thì TC chạy với oracle sai, fail, rồi `/qc-report` phân loại
289
+ > *product-gap* và in một `/report-bug`: một lỗ hổng **tài liệu** đi ra ngoài đội QC thành **phiếu
290
+ > lỗi sản phẩm** gửi PO.
291
+ >
292
+ > `/qc-design-test` §Guard 🚫 Block **tự gỡ** các dấu này khi chạy lại. Trạm này là **lưới bắt phía
293
+ > sau** cho ca guard đó không chạy (TC sửa tay, hoặc gap được trả lời sau lần chạy trạm 3 cuối).
294
+ - **Script:** khớp `.Test.md` 1-1? Page Object 3 lớp + BasePage gọn? `expect()` không phải bare assert? không hard-code URL/cred/timeout, không `time.sleep`, không Allure? selector theo priority (data-testid→role→…)? 100% TC đã script (không còn Draft)?
295
+
296
+ Sinh findings (mức độ + vị trí + cách sửa), chấm điểm, ra verdict.
297
+
298
+ **KHÔNG tự sửa** file TC hay code. Chỉ nhận xét và chấm điểm — người sửa là `/qc-design-test`
299
+ (vai 1) hoặc `/qc-run-test` (vai 2). *Reviewer tự sửa rồi tự duyệt là bỏ mất cái cổng.*
300
+
301
+ ## Output
302
+
303
+ Ghi vào **`{qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md`** — đứng **cạnh** file TC vừa soát:
304
+
305
+ ```
306
+ {qc_artifact_dir}test-cases/
307
+ ├── TC_<FEATURE>.Test.md
308
+ ├── REVIEW_<FEATURE>.md ← soát file trên
309
+ ├── TC_<FEATURE>_API.Test.md
310
+ └── REVIEW_<FEATURE>_API.md ← soát file trên
311
+ ```
312
+
313
+ ⚠️ **Tên file review KHÔNG có đuôi `.Test.md`.** Đuôi đó là của file test case; gắn vào file
314
+ 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 điểm.
315
+
316
+ ### Chạy lại — ghi đè ở đây AN TOÀN, và đây là lý do
317
+
318
+ *(Ba trạm QC khác — `/qc-analyze` · `/qc-design-test` · `/qc-run-test` — đều ở mức **chặn CỨNG** kèm
319
+ §Chạy lại. Trạm này **không**, và đó là kết luận có chủ ý, không phải chỗ sót.)*
320
+
321
+ `REVIEW_<FEATURE>.md` là **biên bản của một lần soát**. Sinh lại = **soát lại**, đúng bản chất của
322
+ nó — không có trạng thái nào tích luỹ qua các lần chạy, không ô nào người điền tay vào sau.
323
+
324
+ *Khai máy đọc: `bin/trace-schema.json` → `artifact_writers.enrolled.qc-review.has_human_content = false`
325
+ — và **R18 ép khai `why`** chính vì một ngoại lệ có chủ ý trông y hệt một chỗ sót.*
326
+
327
+ > **⚠️ Khai lại nếu điều này hết đúng.** Có ai bắt đầu ghi vào biên bản thứ **không sinh lại được** —
328
+ > chữ ký duyệt, một quyết định *"chấp nhận rủi ro"*, ghi chú thảo luận với dev — thì lệnh này **phải**
329
+ > lên `checkpoint_levels.hard` và có §Chạy lại như `/qc-analyze`.
330
+ >
331
+ > *Lưu ý ngược lại: file TC mà trạm này **soát** thì **có** phần người làm tay, và `/qc-design-test`
332
+ > đã ở mức `hard` vì đúng lý do đó (G78). Trạm này chỉ an toàn ở phần nó **ghi**, không phải phần nó
333
+ > **đọc**.*
334
+
335
+ Khuôn đầy đủ + quy tắc ghi: `shared/review-file-template.md`. Ba điều bắt buộc:
336
+
337
+ - **Điểm `XX/100`** — trừ 5đ mỗi `FAIL`, 2đ mỗi `WARN`. Verdict **suy ra được**:
338
+ `≥80` VÀ không còn `FAIL` chặn → `APPROVED`; ngược lại `NEEDS_FIX`.
339
+ - **Bảng Tổng quan THÊM một hàng mỗi vòng**, không ghi đè — đó là cách duy nhất thấy được điểm
340
+ có tăng không. Các bảng chi tiết thì ghi đè phần của tầng mình.
341
+ - **Hai vai ghi vào CÙNG một file**, phân biệt bằng cột `Tầng`. Chúng cách nhau một trạm, nên
342
+ hàng của vai sau **không được ghi đè** hàng của vai trước.
343
+
344
+ > **Vì sao cổng này phải ghi ra file** *(B13)*. Trước đây lệnh chỉ nói *"sinh findings"* — không
345
+ > nói ghi đâu, dạng gì, và điểm là `A/B/C/D` **không có luật chấm**. Hệ quả: hai người soát ra
346
+ > hai kết quả, và **vòng 2 không so được với vòng 1** — tức không ai biết sửa xong có tốt lên
347
+ > không. Một cổng không để lại dấu vết đo được thì không phải cổng, nó là một lượt đọc.
348
+
349
+ ## Self-Review *(trước khi in Report)*
350
+
351
+ Theo 3 nhóm ở `{paths.qc_skills_dir}/_shared/self-review-principles.md` — **không chép lại ở đây**.
352
+
353
+ - **Bịa:** mỗi finding trỏ được về **dòng cụ thể** trong artifact đang soát — không phải nhận xét
354
+ chung chung? Và **cấm dùng chính field `quote` của finding làm bằng chứng cho nó** — mở lại file
355
+ đọc lại đoạn đó.
356
+ - **Nhảy bước:** đã đi hết bộ tiêu chí của **đúng vai** (test-case hay script), không trộn hai
357
+ bộ? Verdict `APPROVED` phát ra **sau** khi soát đủ, không phải vì "trông ổn"?
358
+ - **Số liệu:** số finding theo mức (critical/major/minor) = đếm thật trên file findings vừa ghi?
359
+
360
+ > **Verdict của lệnh này là cổng cho trạm sau.** Một `APPROVED` phát ra sớm không chỉ sai ở đây —
361
+ > nó mở đường cho `/qc-run-test` sinh script từ một bộ TC chưa đạt. Đây là chỗ self-review đắt
362
+ > nhất nếu bỏ qua.
363
+
364
+ ## Report
365
+
281
366
  **Đọc `.agent/steps/report-footer.md`** và áp đúng khuôn footer trong đó (Status Badge ·
282
- Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
283
-
284
- ```
285
- /qc-review Hoàn tất — {UC-ID} ({soát test-case | soát script}) vòng #{N}
286
- Điểm : {XX}/100 ({fail} FAIL × −5đ · {warn} WARN × −2đ){nếu có vòng trước: " ← vòng #{N-1}: {YY}/100"}
287
- Verdict: {APPROVED | NEEDS_FIX} — {n} findings ({crit} chặn)
288
- File : {qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md (thêm 1 hàng vào bảng Tổng quan)
289
- Self-review: {✅ sạch | ⚠️ {n} điểm cần chú ý — liệt kê}
290
- Next (test-case APPROVED): /qc-run-test {UC-ID}
291
- Next (script APPROVED) : /qc-report {UC-ID} rồi tạo PR
292
- (NEEDS_FIX → fix artifact bị gắn cờ, rồi chạy lại /qc-review {UC-ID})
293
- ```
367
+ Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
368
+
369
+ ```
370
+ /qc-review Hoàn tất — {UC-ID} ({soát test-case | soát script}) vòng #{N}
371
+ Điểm : {XX}/100 ({fail} FAIL × −5đ · {warn} WARN × −2đ){nếu có vòng trước: " ← vòng #{N-1}: {YY}/100"}
372
+ Verdict: {APPROVED | NEEDS_FIX} — {n} findings ({crit} chặn)
373
+ File : {qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md (thêm 1 hàng vào bảng Tổng quan)
374
+ Self-review: {✅ sạch | ⚠️ {n} điểm cần chú ý — liệt kê}
375
+ Next (test-case APPROVED): /qc-run-test {UC-ID}
376
+ Next (script APPROVED) : /qc-report {UC-ID} rồi tạo PR
377
+ (NEEDS_FIX → fix artifact bị gắn cờ, rồi chạy lại /qc-review {UC-ID})
378
+ ```