@educa-corp/sdd-framework 0.9.3 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/bin/build.js +11 -0
  2. package/bin/lint-trace.js +230 -2
  3. package/bin/qc-base-map.json +119 -49
  4. package/bin/self-check.js +54 -0
  5. package/bin/trace-schema.json +58 -4
  6. package/core/FRAMEWORK_VERSION +1 -1
  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 +21 -2
  10. package/core/commands/map-testids.md +88 -8
  11. package/core/commands/qc-analyze.md +429 -472
  12. package/core/commands/qc-design-test.md +251 -207
  13. package/core/commands/qc-plan.md +97 -197
  14. package/core/commands/qc-report.md +76 -60
  15. package/core/commands/qc-review.md +135 -185
  16. package/core/commands/qc-run-test.md +235 -274
  17. package/core/commands/review-tech-docs.md +20 -0
  18. package/core/commands/setup-ai-first.md +5 -5
  19. package/core/commands/update-framework.md +1 -1
  20. package/core/commands/validate-traces.md +1 -1
  21. package/core/modules/qc-playwright/stack-profile.yaml +1 -1
  22. package/core/rules/data-protection.md +52 -0
  23. package/core/rules/workflow.md +1 -1
  24. package/core/skills/qc/_shared/self-review-principles.md +112 -0
  25. package/core/skills/qc/qa-analyst/DOC_GAP.template.md +1 -1
  26. package/core/skills/qc/qa-analyst/spec-breakdown.md +2 -2
  27. package/core/skills/qc/qa-designer/api/auth-chain.md +155 -0
  28. package/core/skills/qc/qa-designer/api/auth-sequence.md +75 -0
  29. package/core/skills/qc/qa-designer/api/common-headers.md +61 -0
  30. package/core/skills/qc/qa-designer/api/crud-sequence.md +122 -0
  31. package/core/skills/qc/qa-designer/api/endpoint.md +231 -0
  32. package/core/skills/qc/qa-designer/api/http-status-codes.md +102 -0
  33. package/core/skills/qc/qa-designer/e2e/journey.md +13 -8
  34. package/core/skills/qc/qa-designer/exploratory/charter.md +2 -0
  35. package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +7 -4
  36. package/core/skills/qc/qa-designer/functional/api.md +87 -18
  37. package/core/skills/qc/qa-designer/functional/gui-feature.md +12 -9
  38. package/core/skills/qc/qa-designer/functional/gui-screen.md +12 -10
  39. package/core/skills/qc/qa-designer/integration/api.md +12 -5
  40. package/core/skills/qc/qa-designer/integration/db.md +12 -6
  41. package/core/skills/qc/qa-designer/integration/gui.md +12 -5
  42. package/core/skills/qc/qa-designer/integration/kafka.md +12 -5
  43. package/core/skills/qc/qa-designer/non-functional.md +12 -5
  44. package/core/skills/qc/qa-designer/shared/action-keywords-glossary.md +91 -0
  45. package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +105 -0
  46. package/core/skills/qc/qa-designer/shared/implicit-scenarios.md +22 -0
  47. package/core/skills/qc/qa-designer/shared/precision-rules.md +198 -0
  48. package/core/skills/qc/qa-designer/shared/read-doc-gap-inputs.md +25 -0
  49. package/core/skills/qc/qa-designer/shared/skill-decision-tree.md +93 -0
  50. package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +243 -0
  51. package/core/skills/qc/qa-planner/risk-model.md +1 -1
  52. package/core/skills/qc/qa-reviewer/script/e2e.md +9 -1
  53. package/core/skills/qc/qa-reviewer/script/exploratory.md +9 -1
  54. package/core/skills/qc/qa-reviewer/script/functional.md +9 -1
  55. package/core/skills/qc/qa-reviewer/script/integration.md +9 -1
  56. package/core/skills/qc/qa-reviewer/script/non-functional.md +9 -1
  57. package/core/skills/qc/qa-reviewer/shared/read-doc-gap-inputs.md +26 -0
  58. package/core/skills/qc/qa-reviewer/shared/review-check-groups.md +207 -0
  59. package/core/skills/qc/qa-reviewer/shared/review-file-template.md +228 -0
  60. package/core/skills/qc/qa-reviewer/test-case/e2e.md +71 -13
  61. package/core/skills/qc/qa-reviewer/test-case/exploratory.md +53 -4
  62. package/core/skills/qc/qa-reviewer/test-case/functional.md +63 -15
  63. package/core/skills/qc/qa-reviewer/test-case/integration.md +64 -12
  64. package/core/skills/qc/qa-reviewer/test-case/non-functional.md +72 -13
  65. package/core/skills/qc/qa-runner/e2e.md +3 -3
  66. package/core/skills/qc/qa-runner/functional/gui-feature.md +9 -3
  67. package/core/skills/qc/qa-runner/functional/gui-screen.md +9 -3
  68. package/core/skills/qc/qa-runner/integration.md +1 -1
  69. package/core/skills/qc/qa-runner/non-functional.md +1 -1
  70. package/core/skills/spec/SKILL.md +1 -1
  71. package/core/steps/context-loader.md +7 -2
  72. package/core/steps/gap-verify.md +67 -0
  73. package/core/steps/report-footer.md +3 -3
  74. package/core/templates/feature.template +1 -0
  75. package/core/templates/tech-design.template.md +1 -0
  76. package/docs/02-concepts/pipeline-steps/09-validate-traces.md +1 -1
  77. package/docs/04-reference/commands.md +1 -1
  78. package/docs/04-reference/trace-schema.md +39 -1
  79. package/docs/explain/00-setup-ai-first.md +1 -1
  80. package/docs/explain/11-map-testids.md +70 -69
  81. package/docs/plans/qc-implementation-log.md +145 -3
  82. package/docs/plans/qc-surgery/00-nhat-ky.md +497 -0
  83. package/docs/plans/qc-surgery/01-checklist.md +92 -0
  84. package/docs/plans/qc-surgery/02-lo-trinh.md +266 -0
  85. package/docs/plans/qc-surgery/buoc/0-01-testid-attr-co-cho-o.md +157 -0
  86. package/docs/plans/qc-surgery/buoc/0-02-mot-nguon-cho-testid-attr.md +135 -0
  87. package/docs/plans/qc-surgery/buoc/0-03-skill-thoi-day-do-dom.md +167 -0
  88. package/docs/plans/qc-surgery/buoc/0-04-may-canh-hop-dong.md +173 -0
  89. package/docs/plans/qc-surgery/buoc/0-05-don-nhan-cot-va-2b.md +133 -0
  90. package/docs/plans/qc-surgery/buoc/0-06-hop-dong-truoc-code.md +226 -0
  91. package/docs/plans/qc-surgery/buoc/1-01-guard-br-tag.md +156 -0
  92. package/docs/plans/qc-surgery/buoc/1-02-guard-sc-coverage.md +153 -0
  93. package/docs/plans/qc-surgery/buoc/1-03-fail-3-nhan.md +176 -0
  94. package/docs/plans/qc-surgery/buoc/1-04-self-review-dung-chung.md +175 -0
  95. package/docs/plans/qc-surgery/buoc/1-05-spec-la-du-lieu.md +164 -0
  96. package/docs/plans/qc-surgery/buoc/1-06-gap-verify-du-bo.md +162 -0
  97. package/docs/plans/qc-surgery/buoc/README.md +85 -0
  98. package/docs/plans/qc-surgery/exec-d0-b1-testid-attr-header.md +147 -0
  99. package/docs/plans/qc-surgery/exec-d0-b2-thong-nhat-nguon-testid-attr.md +152 -0
  100. package/docs/plans/qc-surgery/exec-d0-b3-sua-skill-probe-dom.md +173 -0
  101. package/docs/plans/qc-surgery/exec-d0-b4-may-canh-4-5-6.md +168 -0
  102. package/docs/plans/qc-surgery/exec-d0-b5-don-nhan-lech.md +196 -0
  103. package/docs/plans/qc-surgery/exec-d0-b6-contract-truoc-code.md +350 -0
  104. package/docs/plans/qc-surgery/exec-d1-b1-guard-br-tag.md +129 -0
  105. package/docs/plans/qc-surgery/exec-d1-b2-guard-sc-coverage.md +159 -0
  106. package/docs/plans/qc-surgery/exec-d1-b3-fail-3-bucket.md +158 -0
  107. package/docs/plans/qc-surgery/exec-d1-b4-self-review-principles.md +145 -0
  108. package/docs/plans/qc-surgery/exec-d1-b5-noi-quy-spec-la-du-lieu.md +156 -0
  109. package/docs/plans/qc-surgery/exec-d1-b6-gap-verify-mo-rong.md +179 -0
  110. package/docs/plans/qc-surgery/exec-d2-b1-tach-qc-review.md +166 -0
  111. package/docs/plans/qc-surgery/exec-d2-b2-tach-qc-run-test-atomic.md +267 -0
  112. package/docs/plans/qc-surgery/exec-d2-b3-qc-automation-assess.md +198 -0
  113. package/docs/plans/qc-surgery/exec-d3-b1-qc-report-gate-decision.md +209 -0
  114. package/docs/plans/qc-surgery/exec-d4-b1-qc-design-testdata.md +146 -0
  115. package/docs/plans/qc-surgery/exec-d4-b2-qc-smoke-test.md +179 -0
  116. package/docs/plans/qc-surgery/exec-d4-b3-qc-metrics-va-lint.md +198 -0
  117. package/docs/plans/qc-surgery/exec-d4-b4-lint-spec-injection.md +199 -0
  118. package/package.json +1 -1
@@ -74,7 +74,7 @@ Mọi lệnh chạy chung một **Gate** (model check → target → context-loa
74
74
  | `/generate-code` | `.feature` approved + tech-design | Code + `.trace/*.tsv` | Dev |
75
75
  | `/review-code` | Code | Findings (read-only) | Dev/Lead |
76
76
  | `/fix-bug` | Bug report | Fix + regression test | Dev |
77
- | `/map-testids` | UI code | testid map (FE) | Dev |
77
+ | `/map-testids` | design-spec + BDD (`--from-code`: + UI code) | §4.5.6 Test Selectors + `@trace.testid_attr` | Người viết tech-doc (`--from-code`: Dev) |
78
78
  | `/debug` | Mô tả lỗi | Phân tích (read-only) | Dev |
79
79
 
80
80
  ## 7 · Dev self-test
@@ -94,6 +94,44 @@ public ScoreDto calculate(...) { }
94
94
  | `@trace.revision` | integer, bump mỗi lần sửa — nguồn của `TECHDOC_DRIFT` |
95
95
  | `@trace.status` | `draft` / `in-review` / `approved` — cổng của `/generate-code` DS3 |
96
96
  | `@trace.api_source` | `existing` → chế độ reverse-document, bỏ cổng T7 |
97
+ | `@trace.testid_attr` | **TÊN THUỘC TÍNH** chứa test-id (`data-testid` · `data-test` · `testID` · `ValueKey`…) — **một** giá trị cho cả doc. Khác **GIÁ TRỊ** test-id từng element, cái đó ở §4.5.6. Ghi bởi `/map-testids`; đọc bởi `/generate-code` (emit lên element) và các lệnh `qc-*` (cấu hình locator). |
98
+
99
+ ### Hợp đồng test-id — được máy canh (`testid_contract`)
100
+
101
+ Bảng **§4.5.6 Test Selectors** trong tech-doc là hợp đồng FE↔QC: **3 lệnh đọc**
102
+ (`generate-code`, `qc-run-test`, `qc-design-test`), **2 lệnh ghi** (`generate-tech-docs`,
103
+ `map-testids`). Hai rule của `lint-trace` canh nó:
104
+
105
+ | Rule | Kiểm gì | Mức |
106
+ |---|---|:---:|
107
+ | **T15** | Mọi SC ở cột *"Phục vụ SC"* phải có thật trong `.feature` của nền đó | 🔴 error |
108
+ | **T16** | Có block §4.5 (nền client) mà header thiếu hẳn `@trace.testid_attr` | 🔴 error |
109
+ | | …có nhưng còn ở dạng placeholder `{…}` (chưa chạy `/map-testids`) | ⚠️ warn |
110
+ | **T17** | Id đã khai ở §4.5.6 mà **không có trong code** — FE chưa gắn / gắn sai / element đã đổi *(cần `--code`)* | ⚠️ warn |
111
+ | **T18** | Id nằm trong code mà **không có trong §4.5.6 nào** — gắn ngoài hợp đồng *(cần `--code`)* | ⚠️ warn |
112
+
113
+ > **T17/T18 là WARN, không ERROR.** Id đoán từ thiết kế không sống sót 100%: lúc implement, dev
114
+ > có thể gộp hai element thành một component hoặc tách một thành hai. Đây là **nợ cần thấy**,
115
+ > không phải cái sai chặn người.
116
+ >
117
+ > T18 là **lưới bắt phía sau** cho quyết định ở `/generate-code`: khi §4.5.6 rỗng, lệnh đó cảnh
118
+ > báo rồi **để người quyết** thay vì chặn cứng — chính vì có T18 bắt những id tạm sinh ra ở đó,
119
+ > nên "vẫn sinh" không tạo nợ vô hình.
120
+ >
121
+ > Thiếu `--code` → in `T17/T18 BỎ QUA` tường minh, **không im lặng báo sạch**. Code chưa có id
122
+ > nào của thuộc tính đó (UI chưa viết) → im lặng, không phán "FE chưa gắn" cho cả bảng.
123
+
124
+ > **Phạm vi neo vào sự tồn tại của hợp đồng.** Doc không có §4.5 client → **không kiểm gì**.
125
+ > Dự án backend-only, hay dự án chưa từng chạy `/map-testids`, im lặng hoàn toàn. Hai rule nói
126
+ > *"chỗ nào đã hứa thì phải giữ"*, không nói *"mọi chỗ đều phải có hợp đồng"*. Dòng mẫu của
127
+ > template (còn `{…}`) cũng được bỏ qua — nếu không thì tech-doc vừa sinh ra đã đỏ.
128
+ >
129
+ > **Không vào `gate.blocking`** — đây là nợ cần thấy, không phải cái sai chặn PR. Cùng nhóm với
130
+ > `TECHDOC_DRIFT` / `BDD_DRIFT`; 13/17 cờ audit hiện tại cũng không chặn.
131
+
132
+ Khối `testid_contract` trong `bin/trace-schema.json` khai hai rule này kèm `why`, và
133
+ `self-check` **R8e** báo lỗi nếu `lint-trace.js` không thực sự phát ra chúng — nửa *"máy canh"*
134
+ của luật *"khai tường minh + để máy canh"*.
97
135
 
98
136
  ---
99
137
 
@@ -240,7 +278,7 @@ Ca thứ hai là lý do consumer **phải** chuẩn hoá tập bị ảnh hưở
240
278
 
241
279
  ## Xuất JSON cho panel
242
280
 
243
- `trace-report.json` giữ enum `status` **đúng 4 giá trị** `OK`/`DRIFT`/`GAP`/`UNTRACKED` — VS Code extension "Spec Driven Docs Tools" sống ngoài repo framework và switch trên field này. Row `ORPHANED` xuất ra là `"status": "DRIFT"` + `"orphaned": true`; panel cũ hiện nó như DRIFT (đúng nghĩa, không im lặng), panel mới đọc `orphaned` để hiện nhãn riêng. **TSV giữ nguyên chữ `ORPHANED`** — TSV là nguồn-sự-thật.
281
+ `trace-report.json` giữ enum `status` **đúng 4 giá trị** `OK`/`DRIFT`/`GAP`/`UNTRACKED` — VS Code extension "SDD Board" sống ngoài repo framework và switch trên field này. Row `ORPHANED` xuất ra là `"status": "DRIFT"` + `"orphaned": true`; panel cũ hiện nó như DRIFT (đúng nghĩa, không im lặng), panel mới đọc `orphaned` để hiện nhãn riêng. **TSV giữ nguyên chữ `ORPHANED`** — TSV là nguồn-sự-thật.
244
282
 
245
283
  ---
246
284
 
@@ -44,7 +44,7 @@ Mọi command sau đều đọc `project-context.yaml` + `CLAUDE.md` + `domain-k
44
44
  5. **Step 3 · project-context.yaml** — copy từ `templates/project-context.yaml`, điền `{{PLACEHOLDER}}`. Umbrella: verify/sửa `services` (path phải khớp tên submodule thật — generator để placeholder `TODO-…`).
45
45
  6. **Step 4 · business-dictionary.md** — Canonical Terms / Banned Terms / Enum Registry. *(Umbrella skip — sống trong spec submodule.)*
46
46
  7. **Step 5 · core-entities.md** — entity catalog máy-đọc-được (field, invariant, relationship). *(Umbrella skip.)*
47
- 8. **Step 6 · VS Code extension** — khuyến nghị cài "Spec Driven Docs Tools" (Review Board + Living Docs UI).
47
+ 8. **Step 6 · VS Code extension** — khuyến nghị cài "SDD Board" (Review Board + Living Docs UI).
48
48
  9. **Step 7 · Verify** — checklist theo `project_type` (file/folder tồn tại; umbrella check submodule init).
49
49
 
50
50
  ---
@@ -1,69 +1,70 @@
1
- [← /review-code](10-review-code.md) · [Explain Home](README.md) · [Next: /dev-gen-test →](12-dev-gen-test.md)
2
-
3
- # 11 · `/map-testids` — Dán test-id ổn định cho UI (FE)
4
-
5
- > **Một câu.** Gắn **test-id ổn định** vào các element có hành động trên UI FE và ghi bản đồ selector vào tech-doc §4.5.6 — làm cầu nối để QC Playwright bám selector không vỡ.
6
-
7
- ---
8
-
9
- ## Vấn đề giải quyết
10
-
11
- Test tự động (Playwright) vỡ khi selector đổi (class/text thay đổi). `/map-testids` chuẩn hoá **test-id ổn định** cho mọi element tương tác, đảm bảo component tái dùng forward được test-id, và ghi map để QC dùng — tách concern "làm UI test được" khỏi "viết test".
12
-
13
- ---
14
-
15
- ## Vị trí & tiền đề
16
-
17
- - **Vị trí:** Phase Tech Design / Implementation (FE), giữa code FE và QC.
18
- - **Chặn cứng:** chỉ FE/App (platform guard)BE không UI.
19
-
20
- ---
21
-
22
- ## Input / Output
23
-
24
- **Input:** UI code FE (element có action) + catalog component tái dùng + tech-doc §4.5.
25
-
26
- **Output:** code FE được patch test-id + map §4.5.6 Test Selectors trong tech-doc.
27
-
28
- ---
29
-
30
- ## Các bước xử lý (chi tiết)
31
-
32
- | Step | Việc |
33
- |------|------|
34
- | **0 · Platform guard** | Chỉ FE/App; else STOP |
35
- | **1 · Thu thập element có action** | Quét UI tìm element người dùng tương tác (nút, ô nhập, link…) |
36
- | **2 · Phân giải test-id ổn định** | Đặt test-id ổn định (không phụ thuộc text/class dễ đổi) cho mỗi element |
37
- | **3 · Đảm bảo component tái dùng forward test-id** | Component dùng lại (catalog) phải cho phép truyền test-id xuống sửa component nếu chưa |
38
- | **4 · Patch usage site** (chỉ EXTEND) | Gắn test-id vào nơi dùng, chỉ thêm (không viết đè) |
39
- | **5 · Ghi/làm mới map §4.5.6** | Ghi bảng Test Selectors vào tech-doc để QC bám |
40
- | **6 · Handoff** | Bàn giao cho QC (`/qc-*`) |
41
-
42
- ---
43
-
44
- ## Checkpoint & Gate
45
-
46
- - Không gate chặn; EXTEND-only khi patch (an toàn).
47
-
48
- ---
49
-
50
- ## Cơ chế đặc biệt
51
-
52
- - **Test-id ổn định** — chống test vỡ do đổi visual; nguyên tắc "selector là contract QC↔FE".
53
- - **Forward test-id qua component tái dùng** — sửa gốc component để test-id lan xuống, không hardcode từng chỗ.
54
- - **Map §4.5.6 tech-doc** — QC đọc từ một nguồn, không tự dò.
55
-
56
- ---
57
-
58
- ## 👓 Góc nhìn tối ưu
59
-
60
- - **Lệnh cầu nối FE→QC** — vị trí pipeline hơi mờ (giữa Tech Design & Code). Chạy sớm quá thì UI chưa xong, muộn quá thì QC phải chờ. Đáng làm rõ thời điểm tối ưu.
61
- - **Phụ thuộc catalog component tái dùng** — nếu component không forward được prop test-id, Step 3 phát sinh sửa lan rộng.
62
- - **EXTEND-only** an toàn nhưng nếu test-id sai thì không tự sửa.
63
- - **Không bắt buộc trong golden path** dễ bị bỏ qua, khiến QC selector giòn. Cân nhắc tích hợp vào `/generate-code --phase=ui`.
64
-
65
- ---
66
-
67
- ## Kết nối
68
-
69
- **Trước:** [`/generate-code`](09-generate-code.md) (UI FE) · **Sau:** [`/qc-*`](15-qc-analyze.md) dùng selector đã map.
1
+ [← /review-code](10-review-code.md) · [Explain Home](README.md) · [Next: /dev-gen-test →](12-dev-gen-test.md)
2
+
3
+ # 11 · `/map-testids` — Dán test-id ổn định cho UI (FE)
4
+
5
+ > **Một câu.** Gắn **test-id ổn định** vào các element có hành động trên UI FE và ghi bản đồ selector vào tech-doc §4.5.6 — làm cầu nối để QC Playwright bám selector không vỡ.
6
+
7
+ ---
8
+
9
+ ## Vấn đề giải quyết
10
+
11
+ Test tự động (Playwright) vỡ khi selector đổi (class/text thay đổi). `/map-testids` chuẩn hoá **test-id ổn định** cho mọi element tương tác, đảm bảo component tái dùng forward được test-id, và ghi map để QC dùng — tách concern "làm UI test được" khỏi "viết test".
12
+
13
+ ---
14
+
15
+ ## Vị trí & tiền đề
16
+
17
+ - **Vị trí:** Phase **Tech Design**, sau `/generate-tech-docs` **TRƯỚC** `/review-tech-docs` — tức trước cả `/generate-code`. Chốt hợp đồng test-id ở đây để FE và QC đọc cùng một bản đã đóng băng rồi **chạy song song**.
18
+ - **Hai chế độ:** mặc định (feature mớinguồn là design-spec + BDD, **không đụng code**) · `--from-code` (brownfield — đọc/patch code đã có, chạy một lần mỗi UC cũ).
19
+ - **Chặn cứng:** chỉ FE/App (platform guard) — BE không có UI.
20
+
21
+ ---
22
+
23
+ ## Input / Output
24
+
25
+ **Input:** design-spec (Component Inventory, màn hình) + step `When` của `.feature` FE + tech-doc §4.5.1 (cây component) + catalog component tái dùng. *Chế độ `--from-code` đọc thêm UI code FE.*
26
+
27
+ **Output:** map §4.5.6 Test Selectors + `@trace.testid_attr` ở header tech-doc. *Chế độ `--from-code` còn patch test-id vào code FE.*
28
+
29
+ ---
30
+
31
+ ## Các bước xử lý (chi tiết)
32
+
33
+ | Step | Việc |
34
+ |------|------|
35
+ | **0 · Platform guard** | Chỉ FE/App; else STOP |
36
+ | **1 · Thu thập element action** | Quét UI tìm element người dùng tương tác (nút, ô nhập, link…) |
37
+ | **2 · Phân giải test-id ổn định** | Đặt test-id ổn định (không phụ thuộc text/class dễ đổi) cho mỗi element |
38
+ | **3 · Đảm bảo component tái dùng forward test-id** | Component dùng lại (catalog) phải cho phép truyền test-id xuống sửa component nếu chưa |
39
+ | **4 · Patch usage site** (chỉ EXTEND) | Gắn test-id vào nơi dùng, chỉ thêm (không viết đè) |
40
+ | **5 · Ghi/làm mới map §4.5.6** | Ghi bảng Test Selectors vào tech-doc để QC bám |
41
+ | **6 · Handoff** | Bàn giao cho QC (`/qc-*`) |
42
+
43
+ ---
44
+
45
+ ## Checkpoint & Gate
46
+
47
+ - Không gate chặn; EXTEND-only khi patch (an toàn).
48
+
49
+ ---
50
+
51
+ ## Cơ chế đặc biệt
52
+
53
+ - **Test-id ổn định** — chống test vỡ do đổi visual; nguyên tắc "selector contract QC↔FE".
54
+ - **Forward test-id qua component tái dùng** — sửa gốc component để test-id lan xuống, không hardcode từng chỗ.
55
+ - **Map ở §4.5.6 tech-doc** — QC đọc từ một nguồn, không tự dò.
56
+
57
+ ---
58
+
59
+ ## 👓 Góc nhìn tối ưu
60
+
61
+ - **Lệnh chốt hợp đồng FE↔QC** — vị trí **đã được chốt**: phase Tech Design, trước `/generate-code`. Trước đây vị trí mờ (tài liệu này từng nói 'giữa Tech Design & Code') nên lệnh hay bị bỏ qua; giờ `/generate-tech-docs` trỏ thẳng sang đây, `/review-tech-docs` T6 không cho APPROVED nếu §4.5.6 rỗng.
62
+ - **Phụ thuộc catalog component tái dùng** — nếu component không forward được prop test-id, Step 3 phát sinh sửa lan rộng.
63
+ - **EXTEND-only** an toàn nhưng nếu test-id sai thì không tự sửa.
64
+ - **Đã vào golden path** — `/generate-tech-docs` → **`/map-testids`** → `/review-tech-docs` (T6 chặn nếu §4.5.6 rỗng). `lint-trace` T15/T16 canh bảng, T17/T18 canh bảng-vs-code.
65
+
66
+ ---
67
+
68
+ ## Kết nối
69
+
70
+ **Trước:** [`/generate-tech-docs`](08-generate-tech-docs.md) · **Sau:** [`/review-tech-docs`](07-review-tech-docs.md), rồi rẽ hai nhánh song song — [`/generate-code`](09-generate-code.md) (FE gắn attribute) ∥ [`/qc-design-test`](17-qc-design-test.md) (QC dựng test theo cùng hợp đồng).
@@ -1512,6 +1512,148 @@ xem bản mới có bắt thêm gap thật hay không.
1512
1512
 
1513
1513
  ---
1514
1514
 
1515
+ # ✅ B12 — Rà trạm viết kịch bản kiểm thử theo bản gốc
1516
+
1517
+ Đi theo đúng thứ tự dây chuyền: xong trạm 1 và 2 (B11) thì tới trạm 3 — **trạm quyết định có
1518
+ test hay không có test**.
1519
+
1520
+ ## Hai điều rà ra
1521
+
1522
+ **① Trạm này chưa hề được đụng trong cả đợt merge.** Bản đồ port ghi **21/21 file gốc ở trạng
1523
+ thái "chưa quyết"**. 11 kỹ năng đang chạy đến từ **một nguồn khác** (`lms_autotest`), không phải
1524
+ từ đội QC.
1525
+
1526
+ | | File | Dòng |
1527
+ |---|---|---|
1528
+ | Bản gốc đội QC | 21 | **2.509** |
1529
+ | Framework | 11 | **496** *(~20%)* |
1530
+
1531
+ **② Một lỗi im lặng, cùng lớp với `DOC_GAPS` / `DOC_GAP`:**
1532
+
1533
+ | Ai | Nói tên file là |
1534
+ |---|---|
1535
+ | 2 kỹ năng | `TC_<FEATURE>.md` |
1536
+ | 1 kỹ năng | `TC_<FEATURE>_API.md` |
1537
+ | **4 kỹ năng** | **không nêu tên gì cả** |
1538
+ | Lệnh thiết kế · lệnh chạy · lệnh soát · module Playwright *(13 chỗ)* | `*.Test.md` |
1539
+
1540
+ **Trạm thiết kế ghi ra thứ trạm chạy không tìm thấy.** Và không có gì báo lỗi — file vẫn nằm
1541
+ đó, trạm sau chỉ đơn giản không thấy.
1542
+
1543
+ Framework có **phương pháp** (EP/BVA/bảng quyết định, danh sách nhóm TC); bản gốc có **chi
1544
+ tiết** (cấm từ mơ hồ, khuôn TC, từ điển hành động, bảng tra mã HTTP). Đúng khuôn đã gặp ở B1.
1545
+
1546
+ ## Bốn quyết định
1547
+
1548
+ | # | Chốt | Nghĩa cho người dùng |
1549
+ |---|---|---|
1550
+ | **1** | **Luật ATOMIC, có cả chế độ tách tối đa** | Mỗi test case đúng **một** dòng kết quả mong đợi. Nhiều điểm kiểm → tách thành nhiều TC độc lập |
1551
+ | **2** | **Bỏ bảng trong file test case** | Toàn bộ dạng danh sách, không ký tự `\|` — kể cả mục Tổng hợp và Trace Matrix |
1552
+ | **3** | **Hai file, chia theo "có qua giao diện"** | mặc định → file giao diện (6 nhóm) · `--api` → file API (2 nhóm) · `--all` → cả hai |
1553
+ | **4** | **Lấy trọn 7 file luật chung + cả nhánh API, nhưng VIẾT LẠI 2 file mẫu** | 1.523 dòng |
1554
+
1555
+ ## Chỗ suýt tự bắn vào chân mình
1556
+
1557
+ Nhánh API của bản gốc có 2 file **test case mẫu**. Đọc kỹ thì chúng viết **trước** luật ATOMIC
1558
+ (đội QC chốt 2026-07-09, và văn bản ghi rõ *"ĐẢO rule cũ"*):
1559
+
1560
+ ```
1561
+ MẪU GỐC (cũ hơn luật) ĐÃ VIẾT LẠI
1562
+ **Expected:** #### Expected Result
1563
+ - HTTP 201; body.id = x; - HTTP 201 AND body.id exists
1564
+ bản ghi có trong DB
1565
+ ▲ ba kết cục nối bằng ";" → TC_002: body.<field> = <giá trị>
1566
+ mã: API-<FEATURE>-001 → TC_003: DB có bản ghi id = body.id
1567
+ ▲ hệ mã khác mã: TC_<FEATURE>_NNN
1568
+ ```
1569
+
1570
+ **Lấy nguyên hai file này là dạy AI làm ngược đúng cái luật vừa chốt** — vì mẫu cụ thể luôn
1571
+ thắng luật trừu tượng. Đã viết lại cả hai, và kiểm bằng máy: **13/13 khối kết quả mong đợi có
1572
+ đúng 1 dòng**.
1573
+
1574
+ Cũng bỏ 26 dòng là **bản nháp cũ** của chính họ: một bảng tra mã lỗi 14 dòng nằm gọn trong bảng
1575
+ 95 dòng, một file chuỗi gọi 12 dòng nằm gọn trong hai file dài hơn. Lấy cả hai là có hai bảng
1576
+ tra cùng một thứ, rồi chúng lệch nhau.
1577
+
1578
+ ## Bốn thứ giờ mới có
1579
+
1580
+ | Luật | Nó chặn điều gì |
1581
+ |---|---|
1582
+ | **Cấm 9 cụm từ mơ hồ** | *"hiển thị đúng"* · *"hoạt động bình thường"* · *"không lỗi"* → bắt viết giá trị đo được. Phép thử: **hai QC đọc có ra cùng một kết luận đỗ/trượt không?** |
1583
+ | **Khuôn TC + luật ATOMIC** | Mỗi TC một kết cục; mẫu đầy đủ; 5 bẫy khi đánh số lại hàng loạt |
1584
+ | **Cây quyết định chọn tầng** | ~12 ví dụ phân biệt: *"dropdown có placeholder"* = giao diện, *"dropdown hiện đúng N mục từ API"* = tích hợp |
1585
+ | **Từ điển hành động** | Một hành động **một** từ: Click (web) / Tap (mobile) / Enter (nhập) — cấm dùng Type, Input, Fill lẫn lộn |
1586
+
1587
+ Thêm **kiểm trùng lặp** — thứ framework trước đây **không có gì cả**. Nó quan trọng hơn sau khi
1588
+ bật chế độ tách tối đa: nhân một TC trùng lên 5 mảnh thì thành 5 TC trùng, và không ai đếm
1589
+ được nữa. Nên kiểm trùng phải chạy **trước** khi tách.
1590
+
1591
+ Và B11 vừa gom mọi UC vào **một thư mục** — nên **trùng chéo UC** giờ mới thực sự nhìn thấy
1592
+ được, và mới thực sự xảy ra. Hai UC của cùng tính năng rất hay dùng lại một luật nghiệp vụ;
1593
+ gặp thì trỏ trace về UC nguồn, **không viết lại**.
1594
+
1595
+ ## Chín bản của một luật → một bản
1596
+
1597
+ Khối *"Format file TC"* trước đây **bị chép ở 9 kỹ năng** và câu chữ đã lệch nhau. Giờ một
1598
+ bản dùng chung, 9 kỹ năng trỏ về. **Cùng bệnh 5-bản mà B11 vừa chữa** — và lần này nó không
1599
+ tiết kiệm dòng, nó chỉ bỏ đi khả năng chín bản nói khác nhau.
1600
+
1601
+ Cũng bỏ chữ **"hoặc"**: hai kỹ năng từng ghi *"file riêng **hoặc** gộp trong file feature"*.
1602
+ Chữ "hoặc" nghĩa là AI tự chọn mỗi lần một kiểu — nên hai lần chạy cùng một tính năng có thể ra
1603
+ hai cấu trúc thư mục khác nhau.
1604
+
1605
+ ## Hai lần bị máy bắt lỗi — và đó là điểm sáng
1606
+
1607
+ **Lần 1 — self-check chặn.** Tôi dồn phần `@trace.testid_attr` sang file dùng chung, làm lệnh
1608
+ không còn nhắc tag nữa. Rule R3 đỏ ngay: *"schema khai `qc-design-test` là consumer nhưng lệnh
1609
+ KHÔNG nhắc tới nó"*. Đúng — tôi gộp quá tay. Đã trả lại ở lệnh.
1610
+
1611
+ **Lần 2 — bộ test chặn.** `qc-scope.md` (B11) được 5 lệnh nạp, nên nó bị nướng 5 bản vào 5 file
1612
+ lệnh. Cộng thêm phần B12, tổng vượt ngưỡng: **1203 KB / ngưỡng 1200**. Framework đã có cơ chế
1613
+ cho đúng ca này (đọc-lúc-chạy thay vì nướng vào), chỉ là chưa dùng cho file đó. Chuyển xong:
1614
+ **1174 KB**.
1615
+
1616
+ > Cả hai lỗi đều là **lỗi của tôi**, và **cả hai đều do máy bắt, không phải do tôi đọc lại**.
1617
+ > Đây chính là lập luận cho mục còn treo 2b: thứ có máy canh thì không đi lệch.
1618
+
1619
+ ## Bịt một điểm mù của chính bộ máy canh
1620
+
1621
+ Cập nhật bản đồ port xong, self-check **xanh** — nhưng `functional/api.md` nhận nội dung port mà
1622
+ **không đóng dấu nguồn gốc** nào. Đọc lại luật thì rõ vì sao: nó so dấu với bản đồ **khi file có
1623
+ khai**. File không khai gì thì nó im lặng.
1624
+
1625
+ Đã thêm một nhánh mới: **target đã port thì PHẢI khai** nguồn gốc, không chỉ "khai đúng nếu có
1626
+ khai". Và **thử cháy thật** cả hai góc (bỏ cả hai dòng · bỏ một dòng) — kêu đúng cả hai lần.
1627
+
1628
+ Mất dấu nguồn gốc ở file đích nghĩa là: bản đồ biết file này port từ đâu, còn **người mở file
1629
+ thì không** — và lần đồng bộ sau, mọi thứ thành đoán.
1630
+
1631
+ ## Đã kiểm chứng
1632
+
1633
+ | Phép kiểm | Kết quả |
1634
+ |---|---|
1635
+ | Dựng lại toàn bộ | 41/41 ✅ |
1636
+ | Bộ kiểm tra nội bộ | sạch (giờ có **17** nhánh luật) ✅ |
1637
+ | Bộ test tự động | **199/199** ✅ |
1638
+ | Tổng kích thước lệnh | 1174 KB / ngưỡng 1200 ✅ |
1639
+ | Tên file cũ còn sót | **0** |
1640
+ | Lệnh "in bảng" trong kỹ năng thiết kế | **0** |
1641
+ | Dấu vết mẫu cũ trong nhánh API | **0** |
1642
+ | Khối kết quả mong đợi đúng 1 dòng | **13/13** |
1643
+ | Entry "chưa quyết" của trạm này | **21 → 0** |
1644
+ | Target đã port có đủ dấu nguồn gốc | **23/23** |
1645
+ | File mới tới đủ ba tầng (nguồn → đóng gói → đang chạy) | **13/13/13** |
1646
+
1647
+ ## Cố ý chưa làm
1648
+
1649
+ | Việc | Vì sao |
1650
+ |---|---|
1651
+ | **Máy kiểm cấu trúc file test case** | Vẫn là năng lực mới, và vẫn chờ kết quả phép thử của trạm 1. Nhưng B12 làm nó **rẻ hơn hẳn**: cả hai luật mới đều **đếm được** — "0 ký tự `\|`" và "1 dòng mỗi kết quả". Nếu phép thử kết luận cần máy kiểm thì làm một lượt cho cả file gap và file test case |
1652
+ | **4 file tầng test của bản gốc** *(ui · e2e · integration · nfr — 935 dòng)* | Đã ghi `skipped` **kèm lý do**, không để "chưa quyết". Framework tách tầng UI thành 3 kỹ năng theo cây quyết định thay vì một file 341 dòng; phần khuôn TC và độ chính xác **đã tách ra dùng chung**. Còn lại là phần khai kiến trúc agent — framework không có. Đối chiếu nội dung từng tầng để dành |
1653
+ | **3 trạm còn lại** | Đi theo thứ tự dây chuyền. Trạm soát là trạm kế tiếp, và nó **tiêu thụ** đúng chuẩn B12 vừa đặt ra — làm sau là đúng thứ tự |
1654
+
1655
+ ---
1656
+
1515
1657
  # Tổng kết
1516
1658
 
1517
1659
  | | Quyết định ở B7 | Bằng chứng | |
@@ -1554,7 +1696,7 @@ rồi, giờ bắt nó **so** với hai tài liệu kia"*. Không nạp thêm fi
1554
1696
 
1555
1697
  # Các bước còn lại
1556
1698
 
1557
- **Mười hai bước B0–B11 đã xong.** Không còn bước nào đang chờ quyết định để bắt đầu.
1699
+ **Mười ba bước B0–B12 đã xong.** Không còn bước nào đang chờ quyết định để bắt đầu.
1558
1700
 
1559
1701
  Nhưng có **hai việc chưa validate** và **bốn món nợ** — xem §Còn treo ở cuối.
1560
1702
  Mô tả kế hoạch gốc nằm ở [`qc-merge-plan.md`](qc-merge-plan.md).
@@ -1568,7 +1710,7 @@ Mô tả kế hoạch gốc nằm ở [`qc-merge-plan.md`](qc-merge-plan.md).
1568
1710
  Sau mỗi bước, toàn bộ hệ thống được dựng lại và kiểm tra tự động:
1569
1711
 
1570
1712
  - 41/41 mẫu lệnh dựng thành công
1571
- - Bộ kiểm tra nội bộ báo sạch
1713
+ - Bộ kiểm tra nội bộ báo sạch (17 nhánh luật sau B12)
1572
1714
  - Nội dung mới đã lan đủ ba tầng: bản nguồn → bản đóng gói → bản đang chạy
1573
1715
  - **9** dấu nguồn gốc đều được kiểm chứng khớp với file gốc thật
1574
1716
  - Báo khói đã **thử cháy thật** cả 5 nhánh — không giao một cái chưa bao giờ kêu
@@ -1579,7 +1721,7 @@ Sau mỗi bước, toàn bộ hệ thống được dựng lại và kiểm tra
1579
1721
 
1580
1722
  | # | Câu | Mức | Ai quyết |
1581
1723
  |---|---|---|---|
1582
- | **1** | Chạy thử trên một tính năng thật — **mười hai bước, chưa một lần chạy**. Sau B11 phép thử này còn quan trọng hơn: nó là cách duy nhất biết bản cấp tính năng có bắt được mâu thuẫn chéo UC, và có theo đúng template hay không. Ước lượng chi phí của tôi đã sai 3 lần, đều ước thấp | 🔴 chưa validate | bạn (cần spec thật) |
1724
+ | **1** | Chạy thử trên một tính năng thật — **mười ba bước, chưa một lần chạy**. Sau B11 phép thử này còn quan trọng hơn: nó là cách duy nhất biết bản cấp tính năng có bắt được mâu thuẫn chéo UC, và có theo đúng template hay không. Ước lượng chi phí của tôi đã sai 3 lần, đều ước thấp | 🔴 chưa validate | bạn (cần spec thật) |
1583
1725
  | **2** | Đưa nhật ký cho đội QC xem — họ là chủ sở hữu các kỹ năng này, và định dạng họ nhận đã đổi **hai lần** (B9 rồi B11) | 🟠 | bạn |
1584
1726
  | **2b** | **Máy kiểm cấu trúc file gap** — bệnh *"không theo template"* vẫn chưa có gì chặn bằng máy. Hiện chỉ có chỉ thị bằng văn xuôi, tức **cùng loại** với câu chỉ đường đã thất bại, chỉ mạnh hơn | 🟠 chưa chữa | bạn (sau khi chạy thử B11) |
1585
1727
  | **2c** | `Blocker` ↔ `Critical` — đổi trạm chạy test đọc `Critical` (một dòng) thay vì bắt đội QC đổi thói quen. Kết quả hôm trước cho thấy đổi từ ngữ của họ làm **tăng** khả năng lệch | 🟡 | bạn |