@educa-corp/sdd-framework 0.9.7 → 0.9.8

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/qc-base-map.json +13 -11
  2. package/bin/self-check.js +49 -4
  3. package/bin/trace-schema.json +3226 -3187
  4. package/core/FRAMEWORK_VERSION +1 -1
  5. package/core/commands/qc-analyze.md +2 -2
  6. package/core/commands/qc-automation-assess.md +3 -3
  7. package/core/commands/qc-design-script.md +60 -30
  8. package/core/commands/qc-design-test.md +79 -7
  9. package/core/commands/qc-plan.md +1 -1
  10. package/core/commands/qc-report.md +85 -76
  11. package/core/commands/qc-review-script.md +25 -16
  12. package/core/commands/qc-review-testcase.md +8 -7
  13. package/core/commands/qc-run-manualtest.md +1 -1
  14. package/core/commands/qc-run-script.md +15 -8
  15. package/core/modules/qc-playwright-ts/module.yaml +13 -0
  16. package/core/modules/qc-playwright-ts/stack-profile.yaml +99 -0
  17. package/core/modules/qc-wdio-appium/module.yaml +20 -0
  18. package/core/modules/qc-wdio-appium/stack-profile.yaml +107 -0
  19. package/core/skills/qc/qa-analyst/data-flow.md +1 -1
  20. package/core/skills/qc/qa-automation-assess/matrix.md +6 -3
  21. package/core/skills/qc/{qa-runner → qa-designer}/exploratory/session.md +8 -2
  22. package/core/skills/qc/qa-designer/functional/api.md +1 -1
  23. package/core/skills/qc/qa-designer/functional/job.md +128 -0
  24. package/core/skills/qc/qa-designer/integration/api.md +1 -1
  25. package/core/skills/qc/qa-designer/integration/db.md +1 -1
  26. package/core/skills/qc/qa-designer/integration/{kafka.md → queue.md} +20 -4
  27. package/core/skills/qc/qa-designer/shared/skill-decision-tree.md +17 -0
  28. package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +17 -0
  29. package/core/skills/qc/qa-reviewer/script/_shared/review-rules.md +121 -0
  30. package/core/skills/qc/qa-reviewer/script/api/auth.md +49 -0
  31. package/core/skills/qc/qa-reviewer/script/api/endpoint.md +89 -0
  32. package/core/skills/qc/qa-reviewer/script/api/security.md +46 -0
  33. package/core/skills/qc/qa-reviewer/script/exploratory.md +2 -2
  34. package/core/skills/qc/qa-reviewer/script/mobile/e2e.md +41 -0
  35. package/core/skills/qc/qa-reviewer/script/mobile/functional.md +90 -0
  36. package/core/skills/qc/qa-reviewer/script/mobile/integration.md +41 -0
  37. package/core/skills/qc/qa-reviewer/script/mobile/non-functional.md +43 -0
  38. package/core/skills/qc/qa-reviewer/script/web/e2e.md +46 -0
  39. package/core/skills/qc/qa-reviewer/script/web/functional.md +111 -0
  40. package/core/skills/qc/qa-reviewer/script/web/integration.md +46 -0
  41. package/core/skills/qc/qa-reviewer/script/web/non-functional.md +49 -0
  42. package/core/skills/qc/qa-reviewer/shared/read-doc-gap-inputs.md +1 -1
  43. package/core/skills/qc/qa-reviewer/shared/review-file-template.md +26 -7
  44. package/core/skills/qc/qa-reviewer/test-case/e2e.md +1 -1
  45. package/core/skills/qc/qa-reviewer/test-case/exploratory.md +1 -1
  46. package/core/skills/qc/qa-reviewer/test-case/functional.md +1 -1
  47. package/core/skills/qc/qa-reviewer/test-case/integration.md +1 -1
  48. package/core/skills/qc/qa-reviewer/test-case/non-functional.md +1 -1
  49. package/core/skills/qc/qa-script-designer/_shared/api-conventions.md +94 -0
  50. package/core/skills/qc/qa-script-designer/_shared/file-naming-and-folders.md +109 -0
  51. package/core/skills/qc/qa-script-designer/_shared/mobile-conventions.md +196 -0
  52. package/core/skills/qc/qa-script-designer/_shared/web-conventions.md +257 -0
  53. package/core/skills/qc/qa-script-designer/api/auth.md +43 -0
  54. package/core/skills/qc/qa-script-designer/api/endpoint.md +61 -0
  55. package/core/skills/qc/qa-script-designer/api/security.md +41 -0
  56. package/core/skills/qc/qa-script-designer/mobile/e2e.md +35 -0
  57. package/core/skills/qc/qa-script-designer/mobile/functional/feature.md +32 -0
  58. package/core/skills/qc/qa-script-designer/mobile/functional/screen.md +42 -0
  59. package/core/skills/qc/qa-script-designer/mobile/integration.md +39 -0
  60. package/core/skills/qc/qa-script-designer/mobile/non-functional.md +39 -0
  61. package/core/skills/qc/qa-script-designer/web/e2e.md +36 -0
  62. package/core/skills/qc/qa-script-designer/web/functional/api.md +39 -0
  63. package/core/skills/qc/qa-script-designer/web/functional/gui-feature.md +34 -0
  64. package/core/skills/qc/qa-script-designer/web/functional/gui-screen.md +42 -0
  65. package/core/skills/qc/qa-script-designer/web/integration.md +43 -0
  66. package/core/skills/qc/qa-script-designer/web/non-functional.md +42 -0
  67. package/core/skills/qc/qa-script-runner/mobile/run.md +38 -0
  68. package/core/skills/qc/qa-script-runner/report.md +41 -0
  69. package/core/skills/qc/qa-script-runner/web/run.md +48 -0
  70. package/core/steps/qc-scope.md +43 -0
  71. package/core/steps/report-footer.md +2 -2
  72. package/docs/02-concepts/pipeline-steps/07-dev-selftest.md +1 -1
  73. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +10 -10
  74. package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +1 -1
  75. package/docs/02-concepts/traceability.md +1 -1
  76. package/docs/03-guides/developer.md +1 -1
  77. package/docs/03-guides/tester-qa.md +40 -12
  78. package/docs/04-reference/commands.md +1 -1
  79. package/docs/04-reference/modules.md +2 -1
  80. package/docs/explain/17-qc-design-test.md +2 -2
  81. package/docs/explain/19-qc-run-test.md +4 -4
  82. package/docs/explain/20-qc-report.md +1 -1
  83. package/docs/explain/23-fix-bug.md +2 -2
  84. package/docs/plans/qc-surgery/01-checklist.md +18 -6
  85. package/docs/plans/qc-surgery/PLAN_v2.md +295 -0
  86. package/docs/plans/qc-surgery/exec-S-ap-stack-typescript.md +420 -0
  87. package/docs/plans/qc-surgery/exec-S0-guard-cam-stack-cu.md +400 -0
  88. package/docs/plans/qc-surgery/exec-S1-hai-module-thay-qc-playwright.md +267 -0
  89. package/docs/plans/qc-surgery/exec-S2-qa-runner-thanh-script-designer-runner.md +340 -0
  90. package/docs/plans/qc-surgery/exec-S3-viet-lai-tieu-chi-review-script.md +322 -0
  91. package/docs/plans/qc-surgery/exec-S5-an-theo-don-dau-vet-stack-cu.md +292 -0
  92. package/package.json +1 -1
  93. package/core/modules/qc-playwright/stack-profile.yaml +0 -66
  94. package/core/skills/qc/qa-reviewer/script/e2e.md +0 -95
  95. package/core/skills/qc/qa-reviewer/script/functional.md +0 -109
  96. package/core/skills/qc/qa-reviewer/script/integration.md +0 -99
  97. package/core/skills/qc/qa-reviewer/script/non-functional.md +0 -134
  98. package/core/skills/qc/qa-runner/e2e.md +0 -49
  99. package/core/skills/qc/qa-runner/functional/api.md +0 -35
  100. package/core/skills/qc/qa-runner/functional/gui-feature.md +0 -57
  101. package/core/skills/qc/qa-runner/functional/gui-screen.md +0 -61
  102. package/core/skills/qc/qa-runner/integration.md +0 -47
  103. package/core/skills/qc/qa-runner/non-functional.md +0 -49
  104. package/core/skills/qc/qa-runner/report/report.md +0 -37
@@ -1 +1 @@
1
- 0.9.7
1
+ 0.9.8
@@ -6,7 +6,7 @@ ported_from: ai-automation-qc-base
6
6
 
7
7
  # /qc-analyze — QC Requirement Analysis
8
8
 
9
- > Stage 1 của QC automation pipeline native (qc-analyze → qc-plan → qc-design-test → qc-review-testcase → qc-design-script → qc-review-script → qc-run-script → qc-report). Port từ qa-analyst của team QC. Markdown-first: không có script ở đây.
9
+ > Trạm 1/9 của dây chuyền QC automation (qc-analyze → qc-plan → qc-design-test → qc-review-testcase → qc-automation-assess → qc-design-script → qc-review-script → qc-run-script ∥ qc-run-manualtest → qc-report). Port từ qa-analyst của team QC. Markdown-first: không có script ở đây.
10
10
 
11
11
  ## Gate
12
12
 
@@ -284,7 +284,7 @@ ngược về `{id}` của §12 để không đếm hai lần.
284
284
  Bạn là **QC Analyst** — stage đầu tiên của QC automation pipeline. Lấy requirement
285
285
  chính thức (PRD + BDD `.feature` + design-spec) và phân rã thành một mô tả requirement
286
286
  CÓ CẤU TRÚC: function, business rule, data flow, acceptance criteria. Bạn **không**
287
- viết test case chi tiết hay Python (đó là qc-design-test / qc-design-script).
287
+ viết test case chi tiết hay script tự động (đó là qc-design-test / qc-design-script).
288
288
 
289
289
  Ranh giới với `/qc-plan`: bạn trả lời *"requirement là gì?"*; qc-plan trả lời *"rủi ro ở đâu,
290
290
  hỏi dev gì?"*. Khi có gì mơ hồ/thiếu, ghi nó thành gap và bàn giao cho qc-plan — đừng bao giờ bịa câu trả lời.
@@ -6,7 +6,7 @@ ported_from: ai-automation-qc-base
6
6
 
7
7
  # /qc-automation-assess — Quyết định "cái nào máy chạy, cái nào phải tay"
8
8
 
9
- > Chạy **sau** `/qc-review-testcase` (chỉ nhận TC `APPROVED`) và **trước** `/qc-design-script`.
9
+ > **Trạm 5/9** của dây chuyền QC automation — sau `/qc-review-testcase` (chỉ nhận TC `APPROVED`), trước `/qc-design-script`.
10
10
  > Ghi `AUTOMATION_ASSESSMENT.md` — bảng quyết định `Automatable: Y/N` kèm lý do chuẩn hoá, và là
11
11
  > **nguồn duy nhất** cho ba trạm sau.
12
12
 
@@ -232,8 +232,8 @@ Với mỗi UC của PRD, đọc `{qc_artifact_dir}test-cases/REVIEW_<FEATURE>.m
232
232
 
233
233
  | Đọc được | Làm gì |
234
234
  |---|---|
235
- | `APPROVED` | đưa TC của UC đó vào lượt đánh giá |
236
- | `NEEDS_FIX` · không có file | **LOẠI khỏi lượt** — và **liệt kê ra trong report** kèm trạng thái thật |
235
+ | `APPROVED` · `APPROVED_WITH_SUGGESTIONS` | đưa TC của UC đó vào lượt đánh giá |
236
+ | `REVISION_REQUIRED` · `REJECTED` · không có file | **LOẠI khỏi lượt** — và **liệt kê ra trong report** kèm trạng thái thật |
237
237
 
238
238
  > **`%Automated/Total` tính trên mẫu số CHỈ GỒM TC đã đánh giá**, và in kèm số TC bị loại. Để
239
239
  > không ai đọc *"100%"* mà tưởng đã phủ cả PRD.
@@ -6,7 +6,7 @@ ported_from: ai-automation-qc-base
6
6
 
7
7
  # /qc-design-script — QC Script Generation (sinh script, KHÔNG chạy)
8
8
 
9
- > Stage 5 của QC automation pipeline native. Chuyển `.Test.md` **đã `APPROVED`** thành script +
9
+ > Trạm 6/9 của dây chuyền QC automation. Chuyển `.Test.md` **đã `APPROVED`** thành script +
10
10
  > Page Object. **Không chạy test, không ghi sổ trace** — đó là việc của `/qc-run-script`.
11
11
 
12
12
  ## Gate
@@ -214,8 +214,8 @@ Bỏ vế ghi thì trạm sau không có gì để so; bỏ vế so thì stamp t
214
214
 
215
215
  | Đọc được | Làm gì |
216
216
  |---|---|
217
- | `APPROVED` | đi tiếp |
218
- | `NEEDS_FIX` | **DỪNG** — `❌ Test case chưa đạt. Sửa bằng /qc-design-test {UC-ID}, soát lại bằng /qc-review-testcase {UC-ID}.` |
217
+ | `APPROVED` · `APPROVED_WITH_SUGGESTIONS` | **đi tiếp** — in một dòng bằng chứng:<br/>`✅ Cổng test case đã soát: {verdict} — {đường dẫn file vừa đọc}` |
218
+ | `REVISION_REQUIRED` · `REJECTED` | **DỪNG** — `❌ Test case chưa đạt. Sửa bằng /qc-design-test {UC-ID}, soát lại bằng /qc-review-testcase {UC-ID}.` |
219
219
  | Không có file | **DỪNG** — `❌ Chưa soát test case. Chạy /qc-review-testcase {UC-ID} trước.` |
220
220
 
221
221
  > **Đây là thứ `/qc-run-test` cũ KHÔNG làm được** — nó nhận `REVIEW_<FEATURE>.md` mà không biết
@@ -240,32 +240,62 @@ Bỏ vế ghi thì trạm sau không có gì để so; bỏ vế so thì stamp t
240
240
  **chỉ mục ngược duy nhất** TC → file code; `/qc-run-script` đọc đúng cột này để biết chạy file
241
241
  nào, thay vì suy đường dẫn từ quy ước đặt tên.
242
242
 
243
- ## Role & stack (theo module qc-playwright)
244
-
245
- Bạn là **QC Script Designer**. Sinh Python pytest-playwright script + Page Object từ `.Test.md`.
243
+ ## Role & stack (module theo nền — bảng §2b của `steps/qc-scope.md`)
244
+
245
+ Bạn là **QC Script Designer**. Sinh script test + đối tượng trang/màn/API từ `.Test.md`, theo
246
+ **nền đã phân giải ở §2b** — web · app · system, mỗi nền một hình dạng code khác nhau.
247
+
248
+ Quy tắc stack (BẮT BUỘC — từ `stack-profile.yaml` của module đã phân giải ở §2b):
249
+ - **Markdown-first:** không bao giờ sinh script khi chưa có `.Test.md` đã review.
250
+ - **Phủ đúng TC `Automatable: Y`** của `AUTOMATION_ASSESSMENT.md` — mỗi TC đúng một test,
251
+ không hơn không kém. TC `Y` gặp rào cản kỹ thuật lúc viết → `test.fixme('TC-xxx — {lý do}')`
252
+ + ghi `IMPROVE-xxx`, **không âm thầm bỏ qua**.
253
+ - **Locator từ hợp đồng test-id, KHÔNG scan runtime.** Đọc bảng *Test Selectors* §4.5.6 (block
254
+ platform) của tech-doc gộp tại
255
+ `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` — lọc theo cột
256
+ *"Serves SC"* khớp SC của UC này. Ưu tiên map; fallback chỉ cho element có action mà **không** có
257
+ test-id trong §4.5.6, kèm ghi chú để gap được thêm vào tech-design.
258
+ - **Không hard-code** URL · credential · timeout. **Không chờ cứng.** Data để ở `data/`.
259
+
260
+ > 🔑 **Cách đọc `@trace.testid_attr` và cấu hình thuộc tính test-id KHÔNG viết ở đây** — nó nằm
261
+ > ở `_shared/{web|mobile|api}-conventions.md` của nền, nạp ở §Skills ngay dưới. Lý do gỡ khỏi lệnh
262
+ > *(Bước S · S4, 2026-09-17)*: bảng đó từng tồn tại **hai bản**, và hai bản đã lệch nhau — bản
263
+ > trong lệnh còn ghi API của stack cũ trong khi bản ở skill đã đúng. **Một bảng, một chỗ.**
264
+ >
265
+ > Nội dung vẫn bắt buộc, chỉ đổi chỗ đọc: thuộc tính test-id ≠ mặc định mà không cấu hình trước
266
+ > thì **mọi locator trượt 100 %**, và nó trượt **trông y hệt một bug sản phẩm** — QC sẽ đi mở
267
+ > phiếu lỗi gửi PO thay vì sửa một dòng config.
268
+ >
269
+ > **Vì sao không suy thuộc tính từ platform cho nhanh:** suy từ platform là **phát biểu lại một
270
+ > sự thật đã ghi ở nơi khác** — đúng lớp lỗi mà `bin/trace-schema.json` sinh ra để chống.
246
271
 
247
- Quy tắc stack (BẮT BUỘC từ `modules/qc-playwright/stack-profile.yaml`):
248
- - Markdown-first: không bao giờ sinh script khi chưa có `.Test.md` đã review.
249
- - Page Object extends `BasePage` gọn, 3 lớp: locator `_x()`, action `verb_noun()`, assertion `assert_x()` dùng `expect()`.
250
- - **Locator từ test-id contract (không scan runtime).** Đọc bảng *Test Selectors* §4.5.6 (block platform) của tech-doc gộp tại `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` — bảng gộp mọi UC của platform, **lọc theo cột "Serves SC" khớp SC của UC này** — và dựng mỗi Page Object locator từ test-id ổn định của nó. **Ưu tiên map; fallback** về role/label/text/CSS chỉ cho element có action mà **không** có test-id trong §4.5.6, kèm ghi chú để gap được thêm vào tech-design.
251
- - **TÊN THUỘC TÍNH test-id: đọc `@trace.testid_attr`, KHÔNG tự suy từ platform.**
272
+ ## Skills chọn NỀN rồi TẦNG, nạp MỘT file (`{paths.qc_skills_dir}/qa-script-designer/`)
252
273
 
253
- | Đọc được | Làm |
254
- |---|---|
255
- | web + attr ≠ `data-testid` (vd `data-test` · `data-qa`) | **BẮT BUỘC** cấu hình trước khi dùng `get_by_test_id()`: `playwright.selectors.set_test_id_attribute("{attr}")`. Bỏ bước này thì `get_by_test_id()` vẫn dò `data-testid` mặc định → **trượt 100% locator**. |
256
- | web + attr = `data-testid` | `get_by_test_id("...")` như thường |
257
- | RN / Flutter / native | Dùng đúng cơ chế mà `{attr}` mô tả (`testID` · `Key`/`Semantics(identifier:)` · `accessibilityIdentifier`) |
258
- | **Không tìm thấy field** | **Cảnh báo mềm, KHÔNG im lặng hardcode:** `⚠️ Tech-doc thiếu @trace.testid_attr — fallback theo platform ({attr mặc định}). Nếu FE dùng thuộc tính khác thì MỌI locator sẽ trượt. Chạy /map-testids {UC-ID} để ghi field này.` Rồi mới fallback |
274
+ > 🔴 **DỪNG nếu TC mang lane `job` hoặc `queue`.** Hai hình dạng này có TC *(trạm 3 đã hỗ trợ)*
275
+ > nhưng **chưa có skill sinh script**. Sinh bừa bằng lane `api` là tạo API Object cho một thứ
276
+ > **không endpoint nào** script dịch được, chạy được, kiểm **sai thứ**.
277
+ >
278
+ > ```
279
+ > {UC-ID} {n} TC lane {job|queue} trạm này chưa hỗ trợ hình dạng đó.
280
+ > TC vẫn dùng được: chạy tay qua /qc-run-manualtest, hoặc đánh Automatable: N
281
+ > kèm lý do "chưa có bộ sinh script cho lane {lane}".
282
+ > ```
283
+ >
284
+ > TC lane `api` trong cùng UC thì **vẫn sinh bình thường** — dừng theo TC, không dừng cả UC.
259
285
 
260
- > ** sao không suy từ platform cho nhanh:** suy từ platform là **phát biểu lại một sự thật đã ghi ở nơi khác** — đúng lớp lỗi mà `bin/trace-schema.json` sinh ra để chống. Nó hỏng **im lặng theo kiểu tệ nhất**: test fail "element not found" trông y hệt một bug sản phẩm, nên QC đi mở bug thay vì sửa selector.
261
- - pytest-playwright fixture; mỗi test độc lập; gom theo (role, account) để auth không xen kẽ.
262
- - Không hard-code URL/cred/timeout (dùng `Env.*` / `CONFIG[...]`); không `time.sleep()`; không Allure.
263
- - Phủ **100%** TC mang `Automatable: Y` — mỗi TC có đúng một test.
286
+ **Nạp trước:** `_shared/{web|mobile|api}-conventions.md` + `_shared/file-naming-and-folders.md`
287
+ theo nền đã phân giải `steps/qc-scope.md` §2b. Rồi chọn **MỘT** file lane:
264
288
 
265
- ## Skills chọn layer, nạp MỘT file (`{paths.qc_skills_dir}/qa-runner/`)
289
+ | `active_platform` | File |
290
+ |---|---|
291
+ | `web` · `webview` | `web/functional/{gui-screen,gui-feature,api}.md` · `web/{integration,e2e,non-functional}.md` |
292
+ | `app` · `app-ios` · `app-android` | `mobile/functional/{screen,feature}.md` · `mobile/{integration,e2e,non-functional}.md` |
293
+ | `system` | `api/{endpoint,auth,security}.md` |
266
294
 
267
- `functional/{gui-screen,gui-feature,api}.md`, `integration.md`, `e2e.md`,
268
- `non-functional.md`, `exploratory/session.md`.
295
+ > ⚠️ **Ba nền sinh ba hình dạng code khác nhau.** Web dùng Page Object; app dùng **Screen Object**
296
+ > với thứ tự locator của Appium; `system` dùng **API Object** — không màn hình, không locator,
297
+ > không chờ, và **cấm `expect()` bên trong object**. Nạp nhầm lane là sinh ra thứ chạy được nhưng
298
+ > sai kiến trúc, và `/qc-review-script` sẽ chặn nó bằng `R01`.
269
299
 
270
300
  ---
271
301
 
@@ -293,11 +323,11 @@ bị **chép cứng vào một artifact bền**, và **trạm này chép nó l
293
323
 
294
324
  | Đường dẫn | Nội dung | Người sửa tay? |
295
325
  |---|---|:---:|
296
- | `tests/<project>/test_<feature>.py` | pytest script, 1-1 với `test-cases/` | ✅ **có** — `script-bug` |
297
- | `pages/<feature>_page.py` | Page Object (3 lớp + BasePage) | ✅ **có** — `script-bug` |
326
+ | `tests/{TICKET-ID}/<feature>-<scenario>.spec.ts` | spec, 1-1 với `test-cases/` | ✅ **có** — `script-bug` |
327
+ | `pages/<feature>.page.ts` *(web)* · `api/<resource>.api.ts` *(system)* · `screens/<feature>.screen.ts` *(app)* | đối tượng trang/API/màn | ✅ **có** — `script-bug` |
298
328
  | `{qc_artifact_dir}AUTOMATION_ASSESSMENT.md` — cột `Script file` | đường dẫn script của từng TC | ❌ lệnh ghi |
299
329
 
300
- *(Đường dẫn theo `modules/qc-playwright/stack-profile.yaml` §layout.)*
330
+ *(Đường dẫn theo `§layout.{web|api|mobile}` của module đã phân giải ở §2b — KHÔNG viết cứng tên module.)*
301
331
 
302
332
  **KHÔNG ghi sổ trace.** Sinh script không phải là chạy test — ghi `qc_status` ở đây là khẳng định
303
333
  một điều chưa xảy ra. Đó là việc của `/qc-run-script` và `/qc-run-manualtest`.
@@ -306,9 +336,9 @@ một điều chưa xảy ra. Đó là việc của `/qc-run-script` và `/qc-ru
306
336
 
307
337
  Mỗi test được sinh ra mang scenario nó verify, lấy từ Trace matrix của `.Test.md`:
308
338
 
309
- ```python
310
- # @trace.verifies={UC-ID}-SC{N}
311
- def test_TC_<FEATURE>_001_...(...): ...
339
+ ```typescript
340
+ // @trace.verifies={UC-ID}-SC{N}
341
+ test('TC_<FEATURE>_001 — …', async ({ page }) => { … });
312
342
  ```
313
343
 
314
344
  ## Tag ưu tiên — `@smoke` / `@regression`
@@ -6,7 +6,7 @@ ported_from: ai-automation-qc-base
6
6
 
7
7
  # /qc-design-test — QC Test-Case Design
8
8
 
9
- > Stage 3 của QC automation pipeline native (qc-analyze → qc-plan → qc-design-test → qc-review-testcase → qc-design-script → qc-review-script → qc-run-script → qc-report). Port từ qa-designer của team QC. Sinh test case Markdown (`.Test.md`) — Python đến sau ở /qc-design-script.
9
+ > Trạm 3/9 của dây chuyền QC automation (qc-analyze → qc-plan → qc-design-test → qc-review-testcase → qc-automation-assess → qc-design-script → qc-review-script → qc-run-script ∥ qc-run-manualtest → qc-report). Port từ qa-designer của team QC. Sinh test case Markdown (`.Test.md`) — script tự động đến sau ở /qc-design-script.
10
10
 
11
11
  ## Gate
12
12
 
@@ -234,9 +234,26 @@ Kiểm sự tồn tại của cả ba file dưới `{qc_artifact_dir}`:
234
234
  rồi: /qc-plan {TICKET-ID} {active_platform}
235
235
  ```
236
236
 
237
- **Đủ cả ba → im lặng, đi tiếp.** Guard này **điều kiện vào cửa**, không phải phép đo: "đủ file"
238
- không phải một phát hiện, nên không in dòng nào. *(Khác `Guard BR-tag` và `Guard SC coverage` —
239
- hai cái đó là phép ĐẾM, con số của chúng có giá trị ngay cả khi sạch, nên chúng luôn in.)*
237
+ **Đủ cả ba → IN MỘT DÒNG BẰNG CHỨNG rồi đi tiếp:**
238
+
239
+ ```
240
+ ✅ Đầu vào trạm 3: 3/3 — {qc_artifact_dir}{REQUIREMENT_ANALYSIS,DOC_GAP,TEST_PLAN}.md
241
+ ```
242
+
243
+ > **Vì sao cổng vào cửa PHẢI in, dù "đủ file" không phải một phát hiện** *(sửa 2026-09-17, sau một
244
+ > ca thật)*. Bản trước ghi *"đủ cả ba → im lặng, đi tiếp"* với lý do nghe hợp lý: cổng là điều kiện,
245
+ > không phải phép đo. Cái giá không ai tính: **cổng đạt trong im lặng KHÔNG phân biệt được với cổng
246
+ > chưa bao giờ chạy** — cả hai đều không in gì.
247
+ >
248
+ > **Ca thật:** lệnh chạy trên một PRD mà `{qc_artifact_dir}` **chưa tồn tại**, tự tường thuật
249
+ > *"đủ ba file đầu vào"*, rồi đi tiếp. Không dấu vết nào để đối chiếu, và người dùng chỉ phát hiện
250
+ > vì lệnh sau đó hỏi một câu vô lý.
251
+ >
252
+ > Một dòng in ra làm hai việc mà im lặng không làm được: **bỏ qua thì thấy ngay** *(thiếu dòng)*,
253
+ > và **tường thuật sai thì đối chiếu được** *(đường dẫn in ra, mở là biết)*. Đây không phải nới
254
+ > lỏng luật *"đừng in cái không phải phát hiện"* — mà là phân biệt hai loại: **phép đo** in con số,
255
+ > **cổng vào cửa** in bằng chứng nó đã chạy. Cổng không có bằng chứng thì nó không phải cổng, nó
256
+ > là một lời đề nghị.
240
257
 
241
258
  > **Vì sao DỪNG chứ không cảnh báo rồi chạy.** Guard duy nhất còn lại của trạm này —
242
259
  > `Guard SC coverage` — đối chiếu TC với `.feature`, mà `.feature` ở spec repo thì **luôn có mặt**,
@@ -274,11 +291,65 @@ hai cái đó là phép ĐẾM, con số của chúng có giá trị ngay cả k
274
291
  | `--api` | `TC_<FEATURE>_API.Test.md` | 1 Endpoint · 2 Integration API/DB/Kafka |
275
292
  | `--all` | **cả hai file** | như trên, hai file riêng biệt |
276
293
  | `--atomic-max` | — | bật chế độ tách tối đa (xem dưới) |
294
+ | `--shape=api\|job\|queue` | — | nêu tường minh hình dạng nền `system` — **bắt buộc khi chạy `--yes`** trên UC không suy được |
277
295
 
278
296
  **Câu hỏi phân file:** *"TC này verify được mà **không cần UI** không?"* → **có** = file API ·
279
297
  **không** = file giao diện. Đây đúng là Bước 2 của
280
298
  `{paths.qc_skills_dir}/qa-designer/shared/skill-decision-tree.md`.
281
299
 
300
+ ### Nền `system` — hỏi hình dạng khi không suy được
301
+
302
+ > **Chỉ hỏi khi HAI vế cùng đúng.** Hỏi mọi lần nền là `system` là kiểu hỏng **Ồn**: phần lớn UC
303
+ > `system` **là** API thật và BDD nói rõ; hỏi cả những lần đã rõ thì sau vài lần người ta bấm
304
+ > số 1 cho xong, và cổng đó chết trong khi không ai biết.
305
+
306
+ | Vế | Đo thế nào |
307
+ |---|---|
308
+ | **1** | `active_platform = system` |
309
+ | **2** | **0 dấu hiệu endpoint** — không tìm thấy method/path HTTP trong `.feature` của UC **lẫn** trong tech-doc |
310
+
311
+ Một trong hai vế sai → **đi tiếp, không hỏi**.
312
+
313
+ **Cả hai đúng → in bằng chứng rồi mới hỏi.** Hỏi khơi khơi thì người trả lời cũng đang đoán:
314
+
315
+ ```
316
+ {UC-ID} — nền system, không tìm thấy endpoint nào.
317
+
318
+ BDD nói : "{trích nguyên văn dòng When}"
319
+ Tech-doc : {đã có, không khai endpoint | chưa có}
320
+ Tìm thấy : {n} dòng có method/path HTTP
321
+
322
+ Hình dạng nào?
323
+ 1 API — có endpoint; chưa có trong tech-doc thì chờ tech-doc
324
+ 2 Job chạy ngầm — tự chạy theo lịch/điều kiện, không ai gọi
325
+ 3 Consumer hàng đợi — nằm chờ, có message tới thì xử lý
326
+ ```
327
+
328
+ **Có `--yes`:** không hỏi — **DỪNG** với lỗi rõ ràng. Cùng luật với phân giải nền
329
+ *(`steps/qc-scope.md` §2)*, và cùng lý do: đoán hình dạng là viết test case kiểm sai thứ, mà
330
+ nó vẫn ra một file trông hợp lệ.
331
+
332
+ ```
333
+ ❌ {UC-ID} nền system, không suy được hình dạng (0 dấu hiệu endpoint).
334
+ Chạy headless thì phải nêu tường minh: /qc-design-test {UC-ID} --shape=job --yes
335
+ ```
336
+
337
+ **Ghi câu trả lời vào `Tags` của MỌI TC sinh ra ở lượt này** — ô `<lane>` đã có sẵn trong khuôn
338
+ metadata:
339
+
340
+ | Trả lời | `<lane>` | Skill nạp |
341
+ |---|---|---|
342
+ | 1 API | `api` | `functional/api.md` · `integration/api.md` |
343
+ | 2 Job chạy ngầm | `job` | `functional/job.md` |
344
+ | 3 Consumer hàng đợi | `queue` | `integration/queue.md` |
345
+
346
+ > **Vì sao ghi vào từng TC chứ không một chỗ cho cả PRD.** Một PRD có UC là API và UC là job là
347
+ > chuyện thường. Ghi ở cấp PRD là ép cả PRD thành một kiểu.
348
+ >
349
+ > **Vì sao phải ghi, không chỉ dùng rồi thôi.** Trạm 5 và trạm 6 cũng cần biết hình dạng. Không
350
+ > ghi thì chúng **hỏi lại**, và có thể nhận câu trả lời khác — lúc đó test case và script kiểm
351
+ > hai thứ khác nhau, cả hai đều chạy được, và **không gì bắt được**.
352
+
282
353
  > **Vì sao hai file riêng chứ không một file rồi ghi từng nhóm** *(B12)*. `--api` chạy sau khi
283
354
  > file giao diện đã tồn tại là chuyện thường. Nếu chung một file, lần chạy `--api` phải **giữ
284
355
  > nguyên** năm nhóm kia — mà viết-lại-cả-file là đúng thứ agent hay làm. Hai file thì hai chế
@@ -322,8 +393,8 @@ vế nói về **cùng một** kết cục — ví dụ *"form hiển thị đ
322
393
  ## Role
323
394
 
324
395
  Bạn là **QC Designer** — stage 3. Sinh/bảo trì các file test-case Markdown
325
- (`.Test.md`) từ requirement đã phân tích + plan. Output feed vào qc-design-script (Python) và
326
- qc-review. Bạn **không** viết Python.
396
+ (`.Test.md`) từ requirement đã phân tích + plan. Output feed vào qc-review-testcase rồi
397
+ qc-automation-assess. Bạn **không** viết script tự động.
327
398
 
328
399
  ## Skills (`{paths.qc_skills_dir}/qa-designer/`)
329
400
 
@@ -348,7 +419,8 @@ qc-review. Bạn **không** viết Python.
348
419
  | Feature đa-màn | `functional/gui-feature.md` | file giao diện |
349
420
  | API endpoint | `functional/api.md` | **file API** |
350
421
  | Integration qua UI | `integration/gui.md` | file giao diện |
351
- | Integration API/DB/Kafka | `integration/{api,db,kafka}.md` | **file API** |
422
+ | Integration API/DB/hàng đợi | `integration/{api,db,queue}.md` | **file API** |
423
+ | Job chạy ngầm *(lane `job`)* | `functional/job.md` | **file API** |
352
424
  | End-to-end journey | `e2e/journey.md` | file giao diện |
353
425
  | Non-functional | `non-functional.md` | theo câu hỏi phân file |
354
426
  | Exploratory | `exploratory/{charter,explore-to-functional}.md` | file giao diện |
@@ -6,7 +6,7 @@ ported_from: ai-automation-qc-base
6
6
 
7
7
  # /qc-plan — QC Test Plan & Risk Analysis
8
8
 
9
- > Stage 2 của QC automation pipeline native (qc-analyze → qc-plan → qc-design-test → qc-review-testcase → qc-design-script → qc-review-script → qc-run-script → qc-report). Port từ qa-planner của team QC.
9
+ > Trạm 2/9 của dây chuyền QC automation (qc-analyze → qc-plan → qc-design-test → qc-review-testcase → qc-automation-assess → qc-design-script → qc-review-script → qc-run-script ∥ qc-run-manualtest → qc-report). Port từ qa-planner của team QC.
10
10
 
11
11
  ## Gate
12
12
  # Gate — Quy trình vào chuẩn cho mọi lệnh
@@ -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-report — QC Test Report & Evidence
8
-
9
- > Stage 6 (cuối) của QC automation pipeline native (qc-analyze → qc-plan → qc-design-test → qc-review-testcase → qc-design-script → qc-review-script → qc-run-script → qc-report). Port từ bước report của qa-runner team QC.
10
-
11
- ## Gate
1
+ ---
2
+ version: 1.0
3
+ updated: 2026-06-11
4
+ ported_from: ai-automation-qc-base
5
+ ---
6
+
7
+ # /qc-report — QC Test Report & Evidence
8
+
9
+ > Trạm 9/9 (cuối) của dây chuyền QC automation (qc-analyze → qc-plan → qc-design-test → qc-review-testcase → qc-automation-assess → qc-design-script → qc-review-script → qc-run-script ∥ qc-run-manualtest → qc-report). Port từ bước report của kho QC gốc (xem `bin/qc-base-map.json`).
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ó.
@@ -166,74 +166,83 @@ Mỗi dòng ⚠️/🔴 phải ứng với một trạng thái **context-loader
166
166
  - "N" → dừng, hỏi người dùng muốn thay đổi gì.
167
167
  - Có `--yes` và mức *chặn thường* → coi như "Y", **nhưng vẫn IN khối CHECKPOINT** nếu có cờ
168
168
  🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
169
-
170
-
171
- *Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID. Sinh report từ lần chạy `/qc-run-script` gần nhất. Dùng module **qc-playwright** (pytest-html + Playwright Trace không Allure, không dashboard viết tay).*
172
-
173
- ## Context
169
+
170
+
171
+ *Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID. Sinh report từ lần chạy `/qc-run-script` gần nhất. **Reporter theo nền** — đọc `§reporting` của module đã phân giải ở `steps/qc-scope.md` §2b: `web`·`system` → **Playwright HTML Report + Trace**; `app` **Allure Report v2.x**. Không dashboard viết tay.*
172
+
173
+ > ⚠️ **Hai nền KHÁC NHAU ở chỗ này — đừng "thống nhất" lại.** Luật `No Allure` cũ nay chỉ còn
174
+ > đúng cho web *(`Automation-Standards` §1 + `OQ-01` đóng 2026-06-02: Playwright HTML đủ Phase 1,
175
+ > Allure defer Phase 2)*. Nền mobile thì Allure là **bắt buộc** *(`Mobile-Automation-Standards` §1)*.
176
+ > Đó là quyết định của chuẩn, không phải chỗ sót.
177
+
178
+ ## Context
174
179
  **BẮT BUỘC — đọc `.agent/steps/context-loader.md` và thực thi TOÀN BỘ quy trình trong đó**,
175
180
  rồi mới tiếp tục phần bên dưới.
176
181
 
177
182
  Bỏ qua bước này thì `{paths.*}`, `{tech_stack.*}`, `{conventions.*}`, guardrail từ
178
183
  `project-lessons`, và routing service (chế độ umbrella) đều **chưa được phân giải** — mọi
179
- placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
180
-
181
- ---
182
-
183
- ## Role
184
-
185
- Bạn là stage **QC Report** — biến lần chạy gần nhất thành report + evidence chia sẻ được.
186
-
187
- ## Skill (`{paths.qc_skills_dir}/qa-runner/report/`)
188
-
189
- - `report.md` — tự đủ: pytest-html (`--html=reports/<feature>/report.html
190
- --self-contained-html`) + Playwright Trace (`test-results/<nodeid>/trace.zip`, xem qua
191
- `python3 -m playwright show-trace <file>`), kèm screenshot/evidence đính trên FAIL/SKIP.
192
-
193
- ## Procedure
194
-
195
- 1. Định vị artifact của lần chạy gần nhất cho `{UC-ID}` (report pytest-html + trace).
196
- 2. Sinh/làm mới `reports/<feature>/report.html` (self-contained) và đảm bảo mỗi
197
- FAIL/SKIP có trace + screenshot đính kèm.
198
- 3. Tóm tắt TOTAL / PASS / FAIL / SKIP; với mỗi FAIL gồm lệnh `show-trace`
199
- phân loại script-bug hay product-gap.
200
- 4. **Bàn giao product-gap về spec (nhắc).** Với mỗi FAIL phân loại **product-gap**
201
- (defect thật, impl spec không phải script-bug), in một
202
- `/report-bug {UC-ID} {one-line expected-vs-actual}` sẵn-chạy để QC file nó vào spec repo dùng chung.
203
- BUG_FLOW của `/report-bug` rồi định tuyến root cause (Code / BDD / PRD / Design / Env). Không bao giờ
204
- fake-pass một product-gap giữ FAIL trong `qc_status` cho tới khi fix + chạy lại. **script-bug
205
- KHÔNG được file** (QC fix script và chạy lại). Liệt các lệnh; đừng tự tạo report.
206
-
207
- ## Self-Review *(trước khi in Report)*
208
-
209
- Theo 3 nhóm ở `{paths.qc_skills_dir}/_shared/self-review-principles.md` — **không chép lại ở đây**.
210
-
211
- - **Bịa:** mọi con số trong báo cáo trích được về **một dòng cụ thể** của sổ trace / output
212
- runner / bug report — không nội suy khi thiếu mẫu?
213
- - **Nhảy bước:** đã tổng hợp trên **toàn bộ** SC trong phạm vi, không chỉ những SC có kết quả
214
- đẹp? Đã liệt cả SC `not_run` `flaky`, không im lặng bỏ khỏi bảng?
215
- - **Số liệu:** mọi `%` phép chia thật **và nói rõ mẫu số**? Chỗ thiếu dữ liệu ghi **"chưa đủ
216
- dữ liệu"** thay điền một số cho đủ bảng?
217
-
218
- > **Trạm này nơi số liệu đi ra khỏi đội QC.** Một con số sai các trạm trước còn người trong
219
- > đội nhìn thấy; sai đây là đi vào báo cáo cho Lead/PM. Nhóm 3 vì vậy là nhóm nặng nhất ở đây:
220
- > *"một bảng đầy số sai tệ hơn một bảng có ô trống ghi rõ lý do"*.
221
-
222
- ## Report
223
-
184
+ placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
185
+
186
+ ---
187
+
188
+ ## Role
189
+
190
+ Bạn là stage **QC Report** — biến lần chạy gần nhất thành report + evidence chia sẻ được.
191
+
192
+ ## Skill (`{paths.qc_skills_dir}/qa-script-runner/`)
193
+
194
+ - `report.md` — tự đủ, **theo nền**:
195
+ - `web` · `system` — Playwright HTML Report (`npx playwright show-report`) + Trace
196
+ (`test-results/<test>/trace.zip`, xem qua `npx playwright show-trace <file>`)
197
+ - `app` — Allure Report v2.x (`npx allure generate reports/allure-results --clean && npx allure open`)
198
+
199
+ kèm screenshot/evidence đính trên FAIL/SKIP.
200
+
201
+ ## Procedure
202
+
203
+ 1. Định vị artifact của lần chạy gần nhất cho `{UC-ID}` (HTML report + trace, theo nền).
204
+ 2. Sinh/làm mới `reports/<feature>/report.html` (self-contained) đảm bảo mỗi
205
+ FAIL/SKIPtrace + screenshot đính kèm.
206
+ 3. Tóm tắt TOTAL / PASS / FAIL / SKIP; với mỗi FAIL gồm lệnh `show-trace`
207
+ phân loại script-bug hay product-gap.
208
+ 4. **Bàn giao product-gap về spec ( nhắc).** Với mỗi FAIL phân loại **product-gap**
209
+ (defect thật, impl spec không phải script-bug), in một
210
+ `/report-bug {UC-ID} {one-line expected-vs-actual}` sẵn-chạy để QC file vào spec repo dùng chung.
211
+ BUG_FLOW của `/report-bug` rồi định tuyến root cause (Code / BDD / PRD / Design / Env). Không bao giờ
212
+ fake-pass một product-gap nó giữ FAIL trong `qc_status` cho tới khi fix + chạy lại. **script-bug
213
+ KHÔNG được file** (QC fix script và chạy lại). Liệt kê các lệnh; đừng tự tạo report.
214
+
215
+ ## Self-Review *(trước khi in Report)*
216
+
217
+ Theo 3 nhóm `{paths.qc_skills_dir}/_shared/self-review-principles.md` **không chép lại đây**.
218
+
219
+ - **Bịa:** mọi con số trong báo cáo trích được về **một dòng cụ thể** của sổ trace / output
220
+ runner / bug report không nội suy khi thiếu mẫu?
221
+ - **Nhảy bước:** đã tổng hợp trên **toàn bộ** SC trong phạm vi, không chỉ những SC có kết quả
222
+ đẹp? Đã liệt kê cả SC `not_run` và `flaky`, không im lặng bỏ khỏi bảng?
223
+ - **Số liệu:** mọi `%` phép chia thật **và nói mẫu số**? Chỗ thiếu dữ liệu ghi **"chưa đủ
224
+ dữ liệu"** thay điền một số cho đủ bảng?
225
+
226
+ > **Trạm này là nơi số liệu đi ra khỏi đội QC.** Một con số sai ở các trạm trước còn người trong
227
+ > đội nhìn thấy; sai ở đây là đi vào báo cáo cho Lead/PM. Nhóm 3 vì vậy là nhóm nặng nhất ở đây:
228
+ > *"một bảng đầy số sai tệ hơn một bảng có ô trống ghi rõ lý do"*.
229
+
230
+ ## Report
231
+
224
232
  **Đọc `.agent/steps/report-footer.md`** và áp đúng khuôn footer trong đó (Status Badge ·
225
- Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
226
-
227
- ```
228
- /qc-report Hoàn tất — {UC-ID}
229
- Report: reports/<feature>/report.html (TOTAL {N} · PASS {p} · FAIL {f} · SKIP {s})
230
- Trace : test-results/<nodeid>/trace.zip (python3 -m playwright show-trace <file>)
231
-
232
- Product-gap cần file ({g}): ← chạy các lệnh này để PO/Dev thấy trên /sync (script-bug bị loại)
233
- /report-bug {UC-ID} {gap 1 expected vs actual}
234
- /report-bug {UC-ID} {gap 2 }
235
- (không skip)
236
-
237
- Self-review: {✅ sạch | ⚠️ {n} điểm cần chú ý — liệt kê}
238
- Next: /validate-traces {UC-ID} làm mới Living Docs (qc_status), rồi tạo PR
239
- ```
233
+ Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
234
+
235
+ ```
236
+ /qc-report Hoàn tất — {UC-ID}
237
+ Report: reports/<feature>/report.html (TOTAL {N} · PASS {p} · FAIL {f} · SKIP {s})
238
+ Trace : test-results/<test>/trace.zip (npx playwright show-trace <file>) ← web·system
239
+ Report: reports/allure-results (npx allure open) ← app
240
+
241
+ Product-gap cần file ({g}): ← chạy các lệnh này để PO/Dev thấy trên /sync (script-bug bị loại)
242
+ /report-bug {UC-ID} {gap 1 — expected vs actual}
243
+ /report-bug {UC-ID} {gap 2 …}
244
+ (không có → skip)
245
+
246
+ Self-review: {✅ sạch | ⚠️ {n} điểm cần chú ý liệt kê}
247
+ Next: /validate-traces {UC-ID} ← làm mới Living Docs (qc_status), rồi tạo PR
248
+ ```
@@ -6,7 +6,7 @@ ported_from: ai-automation-qc-base
6
6
 
7
7
  # /qc-review-script — QC Review Gate: script
8
8
 
9
- > Soát **code test + Page Object** đã sinh: khớp `.Test.md`, cấu trúc Page Object, assertion,
9
+ > **Trạm 7/9** của dây chuyền QC automation. Soát **code test + Page Object** đã sinh: khớp `.Test.md`, cấu trúc Page Object, assertion,
10
10
  > selector, hard-code. Cặp với `/qc-review-testcase` — hai lệnh, hai vai, không còn đoán.
11
11
 
12
12
  ## Gate
@@ -214,17 +214,25 @@ trạm sinh script. *Reviewer tự sửa rồi tự duyệt là bỏ mất cái
214
214
  |---|---|
215
215
  | `shared/read-doc-gap-inputs.md` | 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 |
216
216
  | `shared/review-file-template.md` | 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* |
217
+ | `script/_shared/review-rules.md` | **Luật soát dùng chung**: R01–R07 · 4 mức severity · 4 verdict suy từ số đếm · phép kiểm cơ học · đường dẫn theo `§layout` |
217
218
 
218
- **Rồi chọn theo tầng, nạp MỘT file:**
219
- `script/{functional,e2e,integration,non-functional,exploratory}.md`
219
+ **Rồi chọn theo NỀN rồi theo TẦNG, nạp MỘT file** *(nền phân giải ở `steps/qc-scope.md` §2b)*:
220
+
221
+ | `active_platform` | File |
222
+ |---|---|
223
+ | `web` · `webview` | `script/web/{functional,integration,e2e,non-functional}.md` |
224
+ | `app` · `app-ios` · `app-android` | `script/mobile/{functional,integration,e2e,non-functional}.md` |
225
+ | `system` | `script/api/{endpoint,auth,security}.md` |
226
+ | *(mọi nền)* | `script/exploratory.md` — biên bản phiên khám phá, không phải code |
227
+
228
+ > ⚠️ **Ba nền soát ba thứ khác nhau, không phải một checklist đổi tên.** Thứ tự locator của web
229
+ > *(`getByRole` → … → css)* **không tồn tại** ở Appium *(`~accessibilityId` → `id` → `xpath`)*, và
230
+ > lane `api` **không có locator lẫn wait** — nó có API Object với luật *"không `expect()` bên
231
+ > trong"*. Nạp nhầm lane là đi tìm những thứ không tồn tại rồi kết luận "không có lỗi".
220
232
 
221
233
  > ⚠️ **KHÔNG nạp `shared/review-check-groups.md` và §*Kiểm tra cấu trúc TC*.** Hai thứ đó kiểm
222
234
  > **cấu trúc file test case** — áp vào một Page Object là bảo reviewer đi tìm `#### Expected Result`
223
235
  > trong code, rồi gắn nhãn lỗi cho thứ đáng lẽ không có ở đó.
224
- >
225
- > *Ghi chú Đợt 2 · b2:* bộ `script/*` hiện **phẳng theo tầng**. Khi bước 2 chốt stack, nó sẽ tái
226
- > cấu trúc thành `script/{web,mobile}/*` — tiêu chí soát khác nhau theo nền. **Cố ý chưa làm ở
227
- > bước này**: viết tiêu chí cho một stack chưa chốt là viết hai lần.
228
236
 
229
237
  ---
230
238
 
@@ -233,8 +241,8 @@ trạm sinh script. *Reviewer tự sửa rồi tự duyệt là bỏ mất cái
233
241
  - **Khớp `.Test.md` 1-1?** Mỗi TC có đúng một test tương ứng; không test mồ côi, không TC bị bỏ.
234
242
  - **Page Object 3 lớp + BasePage gọn?** Logic điều hướng không rò vào file test.
235
243
  - **`expect()` chứ không phải bare assert?** Assertion phải nói được nó kỳ vọng gì khi đỏ.
236
- - **Không hard-code** URL · credential · timeout. Không `sleep` cố định. Không Allure.
237
- - **Selector theo thứ tự ưu tiên** (`data-testid` → role…), lấy từ §4.5.6 chứ không dò DOM.
244
+ - **Không hard-code** URL · credential · timeout. Không chờ cứng (`waitForTimeout` · `browser.pause`).
245
+ - **Locator theo thứ tự ưu tiên CỦA NỀN** — web `getByRole → … → css` · app `~accessibilityId idxpath` · api không có locator. Lấy từ §4.5.6, không dò DOM.
238
246
  - **100% TC đã script** — không còn TC ở trạng thái `Draft`.
239
247
 
240
248
  Sinh findings (mức độ + vị trí + cách sửa), chấm điểm, ra verdict.
@@ -273,13 +281,14 @@ File **phải** chứa đúng một dòng theo khuôn này, ở §Tổng quan:
273
281
  ```
274
282
  hoặc
275
283
  ```
276
- **Verdict:** NEEDS_FIX
284
+ **Verdict:** REVISION_REQUIRED ← hoặc REJECTED khi có BLOCKER
277
285
  ```
278
286
 
279
- `APPROVED` khi **điểm `≥80` không còn `FAIL` chặn**; ngược lại `NEEDS_FIX`.
287
+ Verdict suy từ **số đếm lỗi**, không từ điểm — `≥1 BLOCKER``REJECTED` · `≥1 MAJOR` `REVISION_REQUIRED` · chỉ MINOR/SUGGESTION → `APPROVED_WITH_SUGGESTIONS` · sạch `APPROVED`. Xem `qa-reviewer/shared/review-file-template.md` §Verdict.
280
288
 
281
289
  > **Đây là contract, không phải định dạng cho đẹp.** `/qc-run-script` (Đợt 2 · b2) **DỪNG** khi
282
- > verdict là `NEEDS_FIX` hoặc chưa có file này. Đổi chuỗi này là làm trạm đó mù — nên nếu phải
290
+ > verdict là `REVISION_REQUIRED` / `REJECTED`, hoặc chưa có file này. Ngưỡng đi tiếp:
291
+ > **`≥ APPROVED_WITH_SUGGESTIONS`** (`AGT-005:132`). Đổi chuỗi này là làm trạm đó mù — nên nếu phải
283
292
  > đổi, đổi ở cả hai nơi trong cùng một commit.
284
293
 
285
294
  ### Chạy lại — ghi đè ở đây AN TOÀN, và đây là lý do
@@ -312,7 +321,7 @@ Theo 3 nhóm ở `{paths.qc_skills_dir}/_shared/self-review-principles.md` — *
312
321
  field `quote` của finding làm bằng chứng cho nó** — mở lại file đọc lại đoạn đó.
313
322
  - **Nhảy bước:** đã đi hết bộ tiêu chí `script/*`, **không** trộn tiêu chí test case vào? Verdict
314
323
  `APPROVED` phát ra **sau** khi soát đủ, không phải vì "trông ổn"?
315
- - **Số liệu:** số finding theo mức (critical/major/minor) = đếm thật trên file vừa ghi?
324
+ - **Số liệu:** số finding theo **bốn mức** (BLOCKER/MAJOR/MINOR/SUGGESTION) = đếm thật trên file vừa ghi, và verdict khớp đúng số đếm đó *(R06)*?
316
325
 
317
326
  > **Verdict của lệnh này là cổng cho trạm chạy.** Một `APPROVED` phát ra sớm cho chạy một bộ script
318
327
  > chưa đạt, và kết quả chạy đó đi thẳng vào `/qc-report` thành số liệu người ta tin.
@@ -325,9 +334,9 @@ Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
325
334
  ```
326
335
  /qc-review-script Hoàn tất — {UC-ID} vòng #{N}
327
336
  Điểm : {XX}/100 ({fail} FAIL × −5đ · {warn} WARN × −2đ){nếu có vòng trước: " ← vòng #{N-1}: {YY}/100"}
328
- Verdict: {APPROVED | NEEDS_FIX} — {n} findings ({crit} chặn)
337
+ Verdict: {APPROVED | APPROVED_WITH_SUGGESTIONS | REVISION_REQUIRED | REJECTED} — {n} findings ({blk} BLOCKER · {maj} MAJOR · {min} MINOR · {sug} SUGGESTION)
329
338
  File : {qc_artifact_dir}test-cases/REVIEW_SCRIPT_<FEATURE>.md (thêm 1 hàng vào bảng Tổng quan)
330
339
  Self-review: {✅ sạch | ⚠️ {n} điểm cần chú ý — liệt kê}
331
- Next (APPROVED) : /qc-report {UC-ID} rồi tạo PR
332
- (NEEDS_FIX → sửa script bị gắn cờ, rồi chạy lại lệnh này)
340
+ Next (≥ APPROVED_WITH_SUGGESTIONS) : /qc-report {UC-ID} rồi tạo PR
341
+ (REVISION_REQUIRED | REJECTED → sửa script bị gắn cờ, rồi chạy lại lệnh này)
333
342
  ```