@educa-corp/sdd-framework 0.9.5 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/bin/build.js +11 -1
  2. package/bin/lint-trace.js +397 -28
  3. package/bin/self-check.js +623 -16
  4. package/bin/trace-schema.json +3187 -1981
  5. package/core/FRAMEWORK_VERSION +1 -1
  6. package/core/commands/amend-prd.md +7 -1
  7. package/core/commands/debug.md +8 -2
  8. package/core/commands/define-product.md +38 -1
  9. package/core/commands/dev-gen-test.md +70 -2
  10. package/core/commands/dev-run-test.md +8 -2
  11. package/core/commands/dev-smoke-test.md +7 -1
  12. package/core/commands/extend-prd.md +7 -1
  13. package/core/commands/fix-bug.md +11 -5
  14. package/core/commands/generate-architecture.md +9 -1
  15. package/core/commands/generate-bdd.md +45 -5
  16. package/core/commands/generate-code.md +44 -5
  17. package/core/commands/generate-design-spec.md +7 -1
  18. package/core/commands/generate-prd.md +9 -1
  19. package/core/commands/generate-spec-manifest.md +7 -1
  20. package/core/commands/generate-tech-docs.md +44 -4
  21. package/core/commands/learn.md +7 -1
  22. package/core/commands/map-testids.md +96 -13
  23. package/core/commands/propose-scenario.md +7 -1
  24. package/core/commands/qc-analyze.md +516 -426
  25. package/core/commands/qc-automation-assess.md +356 -0
  26. package/core/commands/qc-design-script.md +400 -0
  27. package/core/commands/qc-design-test.md +482 -248
  28. package/core/commands/qc-plan.md +141 -94
  29. package/core/commands/qc-report.md +9 -3
  30. package/core/commands/{qc-review.md → qc-review-script.md} +172 -132
  31. package/core/commands/qc-review-testcase.md +409 -0
  32. package/core/commands/qc-run-manualtest.md +401 -0
  33. package/core/commands/{qc-run-test.md → qc-run-script.md} +200 -232
  34. package/core/commands/refine-prd.md +7 -1
  35. package/core/commands/report-bug.md +9 -3
  36. package/core/commands/review-code.md +9 -3
  37. package/core/commands/review-context.md +11 -3
  38. package/core/commands/review-tech-docs.md +11 -3
  39. package/core/commands/setup-ai-first.md +7 -1
  40. package/core/commands/validate-traces.md +27 -6
  41. package/core/modules/qc-playwright/stack-profile.yaml +1 -1
  42. package/core/rules/workflow.md +42 -2
  43. package/core/skills/qc/_shared/self-review-principles.md +2 -2
  44. package/core/skills/qc/qa-analyst/DOC_GAP.template.md +10 -2
  45. package/core/skills/qc/qa-analyst/spec-issue-reporter.md +1 -1
  46. package/core/skills/qc/qa-automation-assess/matrix.md +120 -0
  47. package/core/skills/qc/qa-designer/e2e/journey.md +1 -1
  48. package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +1 -1
  49. package/core/skills/qc/qa-designer/functional/api.md +1 -1
  50. package/core/skills/qc/qa-designer/functional/gui-feature.md +1 -1
  51. package/core/skills/qc/qa-designer/functional/gui-screen.md +1 -1
  52. package/core/skills/qc/qa-designer/integration/api.md +1 -1
  53. package/core/skills/qc/qa-designer/integration/db.md +1 -1
  54. package/core/skills/qc/qa-designer/integration/gui.md +1 -1
  55. package/core/skills/qc/qa-designer/integration/kafka.md +1 -1
  56. package/core/skills/qc/qa-designer/non-functional.md +1 -1
  57. package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +33 -5
  58. package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +34 -5
  59. package/core/skills/qc/qa-planner/test-plan.md +7 -0
  60. package/core/skills/qc/qa-reviewer/script/e2e.md +1 -1
  61. package/core/skills/qc/qa-reviewer/script/exploratory.md +1 -1
  62. package/core/skills/qc/qa-reviewer/script/functional.md +1 -1
  63. package/core/skills/qc/qa-reviewer/script/integration.md +1 -1
  64. package/core/skills/qc/qa-reviewer/script/non-functional.md +1 -1
  65. package/core/skills/qc/qa-reviewer/shared/review-file-template.md +3 -3
  66. package/core/skills/qc/qa-reviewer/test-case/e2e.md +1 -1
  67. package/core/skills/qc/qa-reviewer/test-case/functional.md +1 -1
  68. package/core/skills/qc/qa-reviewer/test-case/integration.md +1 -1
  69. package/core/skills/qc/qa-reviewer/test-case/non-functional.md +1 -1
  70. package/core/skills/qc/qa-runner/e2e.md +2 -2
  71. package/core/skills/qc/qa-runner/functional/gui-feature.md +4 -4
  72. package/core/skills/qc/qa-runner/functional/gui-screen.md +4 -4
  73. package/core/skills/qc/qa-runner/integration.md +1 -1
  74. package/core/skills/qc/qa-runner/non-functional.md +1 -1
  75. package/core/steps/context-loader.md +1 -1
  76. package/core/steps/gate.md +7 -1
  77. package/core/steps/qc-scope.md +67 -11
  78. package/core/steps/qc-stamp.md +142 -0
  79. package/core/steps/report-footer.md +19 -10
  80. package/core/templates/tech-design.template.md +3 -3
  81. package/docs/01-getting-started/quickstart.md +4 -3
  82. package/docs/02-concepts/architecture.md +14 -0
  83. package/docs/02-concepts/glossary.md +8 -0
  84. package/docs/02-concepts/overview.md +3 -2
  85. package/docs/02-concepts/pipeline-steps/04-bdd.md +1 -1
  86. package/docs/02-concepts/pipeline-steps/05-tech-docs.md +21 -5
  87. package/docs/02-concepts/pipeline-steps/06-code.md +12 -2
  88. package/docs/02-concepts/pipeline-steps/07-dev-selftest.md +1 -1
  89. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +65 -16
  90. package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +3 -3
  91. package/docs/02-concepts/pipeline-steps/README.md +4 -3
  92. package/docs/02-concepts/traceability.md +2 -2
  93. package/docs/03-guides/architect.md +2 -2
  94. package/docs/03-guides/developer.md +6 -3
  95. package/docs/03-guides/tester-qa.md +23 -10
  96. package/docs/04-reference/commands.md +9 -4
  97. package/docs/04-reference/trace-schema.md +5 -5
  98. package/docs/explain/07-generate-tech-docs.md +5 -3
  99. package/docs/explain/08-review-tech-docs.md +15 -3
  100. package/docs/explain/09-generate-code.md +30 -4
  101. package/docs/explain/10-review-code.md +1 -1
  102. package/docs/explain/11-map-testids.md +72 -70
  103. package/docs/explain/12-dev-gen-test.md +1 -1
  104. package/docs/explain/15-qc-analyze.md +14 -2
  105. package/docs/explain/16-qc-plan.md +5 -1
  106. package/docs/explain/17-qc-design-test.md +30 -7
  107. package/docs/explain/18-qc-review.md +43 -17
  108. package/docs/explain/19-qc-run-test.md +38 -12
  109. package/docs/explain/20-qc-report.md +8 -5
  110. package/docs/explain/23-fix-bug.md +2 -2
  111. package/docs/explain/README.md +6 -3
  112. package/docs/plans/qc-surgery/01-checklist.md +70 -17
  113. package/package.json +1 -1
@@ -4,6 +4,8 @@
4
4
 
5
5
  *Checkpoint: **chặn CỨNG** — ghi đè PRD đã có → mất changelog, ĐÁNH SỐ LẠI BR, phá @trace.business_rules trong mọi .feature đã sinh. `--yes` KHÔNG bỏ qua được (gate Bước 3a).*
6
6
 
7
+ *Mức cứng chỉ áp khi PRD **đã tồn tại** — và khi đó Bước 1 **DỪNG HẲN**, không cả hỏi Y/N ("Tồn tại → DỪNG. KHÔNG ghi, KHÔNG hỏi Y/N"). PRD chưa có: đi thẳng.*
8
+
7
9
  # Gate — Quy trình vào chuẩn cho mọi lệnh
8
10
 
9
11
  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ó.
@@ -83,7 +85,7 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
83
85
 
84
86
  | Mức | Lệnh nào | `--yes` bỏ qua được? |
85
87
  |---|---|:---:|
86
- | **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
88
+ | **Không chặn** | `/review-code` · `/validate-traces` · `/debug` **KHÔNG phải vì read-only**: cả ba đều CÓ ghi file. Chúng không chặn vì thao tác ghi của chúng hoặc nằm sau một câu hỏi `(Y/N)`, hoặc nằm sau một cờ, hoặc là `append`/dựng-lại-được | — (vốn không có) |
87
89
  | **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
88
90
  | **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
89
91
 
@@ -91,6 +93,12 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
91
93
  `--` khỏi phần resolve target, nên cờ này không ảnh hưởng việc tìm file.) Mở đường chạy
92
94
  headless: `claude -p "/generate-code UC1 --yes"`.
93
95
 
96
+ > **Tên lệnh trong bảng trên có máy canh — `R19`.** Mỗi hàng bảng vừa nêu một mức vừa nêu
97
+ > tên lệnh sẽ bị đối chiếu với `gate.checkpoint_levels`; lệch là build đỏ. Lý do có rule này:
98
+ > ngày 2026-09-16 hai lệnh đổi mức, schema và `commands/*.tmpl` đều sửa, **build vẫn xanh**,
99
+ > mà bảng này lẫn `rules/workflow.md` đều còn liệt chúng ở mức cũ. `R11` chỉ canh
100
+ > `commands/*.tmpl` ↔ schema — *biết có máy canh không bằng biết máy canh **đến đâu***.
101
+
94
102
  > **KHÔNG tự suy mức từ bảng này.** Mỗi lệnh **tự khai** mức của nó ở một dòng `*Checkpoint: …*`
95
103
  > ngay dưới `## Gate` của chính nó — đọc dòng đó, đừng suy diễn. Bảng trên chỉ giải thích ba mức
96
104
  > **nghĩa là gì**.
@@ -84,7 +84,7 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
84
84
 
85
85
  | Mức | Lệnh nào | `--yes` bỏ qua được? |
86
86
  |---|---|:---:|
87
- | **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
87
+ | **Không chặn** | `/review-code` · `/validate-traces` · `/debug` **KHÔNG phải vì read-only**: cả ba đều CÓ ghi file. Chúng không chặn vì thao tác ghi của chúng hoặc nằm sau một câu hỏi `(Y/N)`, hoặc nằm sau một cờ, hoặc là `append`/dựng-lại-được | — (vốn không có) |
88
88
  | **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
89
89
  | **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
90
90
 
@@ -92,6 +92,12 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
92
92
  `--` khỏi phần resolve target, nên cờ này không ảnh hưởng việc tìm file.) Mở đường chạy
93
93
  headless: `claude -p "/generate-code UC1 --yes"`.
94
94
 
95
+ > **Tên lệnh trong bảng trên có máy canh — `R19`.** Mỗi hàng bảng vừa nêu một mức vừa nêu
96
+ > tên lệnh sẽ bị đối chiếu với `gate.checkpoint_levels`; lệch là build đỏ. Lý do có rule này:
97
+ > ngày 2026-09-16 hai lệnh đổi mức, schema và `commands/*.tmpl` đều sửa, **build vẫn xanh**,
98
+ > mà bảng này lẫn `rules/workflow.md` đều còn liệt chúng ở mức cũ. `R11` chỉ canh
99
+ > `commands/*.tmpl` ↔ schema — *biết có máy canh không bằng biết máy canh **đến đâu***.
100
+
95
101
  > **KHÔNG tự suy mức từ bảng này.** Mỗi lệnh **tự khai** mức của nó ở một dòng `*Checkpoint: …*`
96
102
  > ngay dưới `## Gate` của chính nó — đọc dòng đó, đừng suy diễn. Bảng trên chỉ giải thích ba mức
97
103
  > **nghĩa là gì**.
@@ -13,6 +13,11 @@
13
13
  > của PRD (sẽ nổ context).
14
14
 
15
15
  ## Gate
16
+
17
+ *Checkpoint: **chặn CỨNG** — ghi đè/mở rộng tech-doc gộp đã có. Doc chứa **§4.5.6 Test Selectors** do SA viết tay (xem `/map-testids`) và **§12 GAP Register** — cả hai không suy lại được từ BDD. `--yes` KHÔNG bỏ qua được (gate Bước 3a).*
18
+
19
+ *Mức cứng chỉ áp khi trả lời **`Y`** (merge/mở rộng) cho một UC **đã có** nội dung trong doc. UC mới và **`N`** (bỏ qua UC) đi thẳng; doc chưa tồn tại cũng đi thẳng. Xem §Chạy lại.*
20
+
16
21
  # Gate — Quy trình vào chuẩn cho mọi lệnh
17
22
 
18
23
  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ó.
@@ -92,7 +97,7 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
92
97
 
93
98
  | Mức | Lệnh nào | `--yes` bỏ qua được? |
94
99
  |---|---|:---:|
95
- | **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
100
+ | **Không chặn** | `/review-code` · `/validate-traces` · `/debug` **KHÔNG phải vì read-only**: cả ba đều CÓ ghi file. Chúng không chặn vì thao tác ghi của chúng hoặc nằm sau một câu hỏi `(Y/N)`, hoặc nằm sau một cờ, hoặc là `append`/dựng-lại-được | — (vốn không có) |
96
101
  | **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
97
102
  | **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
98
103
 
@@ -100,6 +105,12 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
100
105
  `--` khỏi phần resolve target, nên cờ này không ảnh hưởng việc tìm file.) Mở đường chạy
101
106
  headless: `claude -p "/generate-code UC1 --yes"`.
102
107
 
108
+ > **Tên lệnh trong bảng trên có máy canh — `R19`.** Mỗi hàng bảng vừa nêu một mức vừa nêu
109
+ > tên lệnh sẽ bị đối chiếu với `gate.checkpoint_levels`; lệch là build đỏ. Lý do có rule này:
110
+ > ngày 2026-09-16 hai lệnh đổi mức, schema và `commands/*.tmpl` đều sửa, **build vẫn xanh**,
111
+ > mà bảng này lẫn `rules/workflow.md` đều còn liệt chúng ở mức cũ. `R11` chỉ canh
112
+ > `commands/*.tmpl` ↔ schema — *biết có máy canh không bằng biết máy canh **đến đâu***.
113
+
103
114
  > **KHÔNG tự suy mức từ bảng này.** Mỗi lệnh **tự khai** mức của nó ở một dòng `*Checkpoint: …*`
104
115
  > ngay dưới `## Gate` của chính nó — đọc dòng đó, đừng suy diễn. Bảng trên chỉ giải thích ba mức
105
116
  > **nghĩa là gì**.
@@ -614,7 +625,7 @@ sở hữu (DB) vs lấy live (API ngoài), và thao tác ghi chính.}
614
625
  trong CÙNG nhóm platform (không bao giờ tạo nhóm 4.5 thứ hai cho cùng platform).
615
626
  • §4.5.2–§4.5.5 — tương tự theo màn hình/UC ở chỗ chúng khác nhau.
616
627
  • §4.5.6 Test Selectors — MỘT bảng dùng chung cho cả nhóm platform; cột
617
- "Phục vụ SC" mang (UC · SC) để consumer per-UC lọc row của mình.
628
+ "Serves SC" mang (UC · SC) để consumer per-UC lọc row của mình.
618
629
  Append: platform mới → nhóm "### 4.5 — {platform}" mới; màn hình/UC mới trong
619
630
  platform đã có → thêm sub-block + row vào §4.5.6 (đừng lặp nhóm).
620
631
  Bỏ hẳn §4.5 với PRD backend-only. -->
@@ -670,11 +681,11 @@ sở hữu (DB) vs lấy live (API ngoài), và thao tác ghi chính.}
670
681
  iOS accessibilityIdentifier. Dùng lại CÙNG giá trị id trên web/app cho cùng một
671
682
  element logic.
672
683
  MỘT bảng dùng chung cho cả nhóm platform (phủ mọi màn hình/UC của platform này).
673
- Cột "Phục vụ SC" mang (UC · SC) để consumer per-UC (generate-code / qc) lọc row
684
+ Cột "Serves SC" mang (UC · SC) để consumer per-UC (generate-code / qc) lọc row
674
685
  của mình qua §10. Nhóm §4.5 này vốn đã theo platform, nên platform là ngầm định
675
686
  (khối web → web · SC). -->
676
687
 
677
- | Test-ID | Element | Component (§4.5.1.x) | Action | Phục vụ SC (UC · SC) |
688
+ | Test-ID | Element | Component (§4.5.1.x) | Action | Serves SC (UC · SC) |
678
689
  |---------|---------|----------------------|--------|---------------------|
679
690
  | `{uc}-{screen}-{element}-{type}` | {Nút submit} | {Component} | {submit} | {UC1 · SC1, UC1 · SC3} |
680
691
 
@@ -954,6 +965,35 @@ Nếu `tech_docs_dir` là **local** — tức không có `setup.spec_source` (si
954
965
 
955
966
  ## Output
956
967
 
968
+ ## Chạy lại — tech-doc gộp đã tồn tại *(mặc định MỞ RỘNG, không thay)*
969
+
970
+ Doc gộp cấp PRD được viết dần theo từng UC, nên chạy lại là chuyện thường. Nhưng doc chứa hai
971
+ phần **không suy lại được từ BDD**:
972
+
973
+ | Phần | Ai tạo | Sinh lại được? |
974
+ |---|---|:---:|
975
+ | §1–§11 nội dung kỹ thuật của UC | lệnh này | ✅ |
976
+ | **§4.5.6 Test Selectors** | **SA viết tay** *(đo thật: 28/28 doc dùng quy ước riêng)* | ❌ **không** |
977
+ | **§12 GAP Register** | lệnh này, nhưng `[GAP: Gn]` đã được người xử lý | ❌ đổi là phá |
978
+
979
+ **Khi một UC ĐÃ CÓ nội dung trong doc, in khối này trước khi merge** *(mức chặn CỨNG)*:
980
+
981
+ ```
982
+ ❌ UC{N} đã có nội dung trong: {tech-doc-path}
983
+ Hiện: @trace.revision {r} · @trace.status {status} · §4.5.6 có {n} row
984
+
985
+ Merge/mở rộng UC này có thể đụng:
986
+ • §4.5.6 Test Selectors — SA viết tay, /map-testids đã phải chặn CỨNG vì chính bảng này
987
+ • §12 GAP Register — mã [GAP: Gn] đang được /qc-analyze tham chiếu
988
+ • @trace.bdd_versions — hạ sai là cờ TECHDOC_STALE_VS_BDD tắt nhầm
989
+
990
+ Chỉ muốn thêm UC mới → chọn N cho UC này, Y cho UC mới
991
+ §4.5.6 cần đổi thật → /map-testids {UC-ID} (lệnh sở hữu bảng đó)
992
+ Doc lệch BDD, muốn soát lại → /review-tech-docs {path}
993
+ ```
994
+
995
+ > **UC MỚI (chưa có trong doc) đi thẳng, không chặn** — thêm section mới không đụng gì của ai.
996
+
957
997
  **Đọc `.agent/steps/report-footer.md`** và áp đúng khuôn footer trong đó (Status Badge ·
958
998
  Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
959
999
 
@@ -91,7 +91,7 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
91
91
 
92
92
  | Mức | Lệnh nào | `--yes` bỏ qua được? |
93
93
  |---|---|:---:|
94
- | **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
94
+ | **Không chặn** | `/review-code` · `/validate-traces` · `/debug` **KHÔNG phải vì read-only**: cả ba đều CÓ ghi file. Chúng không chặn vì thao tác ghi của chúng hoặc nằm sau một câu hỏi `(Y/N)`, hoặc nằm sau một cờ, hoặc là `append`/dựng-lại-được | — (vốn không có) |
95
95
  | **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
96
96
  | **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
97
97
 
@@ -99,6 +99,12 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
99
99
  `--` khỏi phần resolve target, nên cờ này không ảnh hưởng việc tìm file.) Mở đường chạy
100
100
  headless: `claude -p "/generate-code UC1 --yes"`.
101
101
 
102
+ > **Tên lệnh trong bảng trên có máy canh — `R19`.** Mỗi hàng bảng vừa nêu một mức vừa nêu
103
+ > tên lệnh sẽ bị đối chiếu với `gate.checkpoint_levels`; lệch là build đỏ. Lý do có rule này:
104
+ > ngày 2026-09-16 hai lệnh đổi mức, schema và `commands/*.tmpl` đều sửa, **build vẫn xanh**,
105
+ > mà bảng này lẫn `rules/workflow.md` đều còn liệt chúng ở mức cũ. `R11` chỉ canh
106
+ > `commands/*.tmpl` ↔ schema — *biết có máy canh không bằng biết máy canh **đến đâu***.
107
+
102
108
  > **KHÔNG tự suy mức từ bảng này.** Mỗi lệnh **tự khai** mức của nó ở một dòng `*Checkpoint: …*`
103
109
  > ngay dưới `## Gate` của chính nó — đọc dòng đó, đừng suy diễn. Bảng trên chỉ giải thích ba mức
104
110
  > **nghĩa là gì**.
@@ -26,15 +26,25 @@ patch, mọi element đều là `new`. Chỉ chạy Step 1 → 2 → 5.
26
26
  >
27
27
  > ```
28
28
  > /review-tech-docs (APPROVED)
29
- > ├──→ /generate-code FE gắn attribute theo hợp đồng
30
- > └──→ /qc-design-test QC viết test case + script theo CÙNG hợp đồng
29
+ > ├──→ /generate-code FE gắn attribute theo hợp đồng
30
+ > └──→ /qc-analyze → /qc-plan → /qc-design-test QC viết test case theo CÙNG hợp đồng
31
31
  > ```
32
32
  >
33
+ > **Cửa vào làn QC là `/qc-analyze`, KHÔNG phải `/qc-design-test`.** Trạm 3 tiêu thụ output của
34
+ > trạm 1–2 (`REQUIREMENT_ANALYSIS.md` · `DOC_GAP.md` · `TEST_PLAN.md`); trỏ thẳng vào nó là chỉ
35
+ > người ta nhảy vào giữa dây chuyền. Cả ba trạm đầu **không cần code**, nên nhánh QC vẫn song song
36
+ > trọn vẹn với `/generate-code` — chỉ trạm 5 `/qc-design-script` mới cần code chạy được.
37
+ >
33
38
  > Hai nhánh **không chờ nhau** vì cùng đọc một bản đã đóng băng, không đọc output của nhau.
34
39
  > Chạy sau code thì QC phải xếp hàng, và `/generate-code` không có gì để đọc nên sẽ tự sinh id
35
40
  > — hợp đồng thành thứ do code quyết định.
36
41
 
37
42
  ## Gate
43
+
44
+ *Checkpoint: **chặn CỨNG** — ghi đè §4.5.6 đã có → ĐỔI id hợp đồng mà SA viết tay, và kéo theo Step 5b hạ `qc_status` + bump `tech_doc_revision` cho một hợp đồng **chưa hỏng**. `--yes` KHÔNG bỏ qua được (gate Bước 3a).*
45
+
46
+ *Mức cứng chỉ áp khi §4.5.6 **đã có row**. Tech-doc chưa có bảng — brownfield thật, ca lệnh này **sinh ra để phục vụ** — đi thẳng, không CHECKPOINT cứng. Xem Step 2 §Bảng đã có id.*
47
+
38
48
  # Gate — Quy trình vào chuẩn cho mọi lệnh
39
49
 
40
50
  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ó.
@@ -114,7 +124,7 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
114
124
 
115
125
  | Mức | Lệnh nào | `--yes` bỏ qua được? |
116
126
  |---|---|:---:|
117
- | **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
127
+ | **Không chặn** | `/review-code` · `/validate-traces` · `/debug` **KHÔNG phải vì read-only**: cả ba đều CÓ ghi file. Chúng không chặn vì thao tác ghi của chúng hoặc nằm sau một câu hỏi `(Y/N)`, hoặc nằm sau một cờ, hoặc là `append`/dựng-lại-được | — (vốn không có) |
118
128
  | **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
119
129
  | **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
120
130
 
@@ -122,6 +132,12 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
122
132
  `--` khỏi phần resolve target, nên cờ này không ảnh hưởng việc tìm file.) Mở đường chạy
123
133
  headless: `claude -p "/generate-code UC1 --yes"`.
124
134
 
135
+ > **Tên lệnh trong bảng trên có máy canh — `R19`.** Mỗi hàng bảng vừa nêu một mức vừa nêu
136
+ > tên lệnh sẽ bị đối chiếu với `gate.checkpoint_levels`; lệch là build đỏ. Lý do có rule này:
137
+ > ngày 2026-09-16 hai lệnh đổi mức, schema và `commands/*.tmpl` đều sửa, **build vẫn xanh**,
138
+ > mà bảng này lẫn `rules/workflow.md` đều còn liệt chúng ở mức cũ. `R11` chỉ canh
139
+ > `commands/*.tmpl` ↔ schema — *biết có máy canh không bằng biết máy canh **đến đâu***.
140
+
125
141
  > **KHÔNG tự suy mức từ bảng này.** Mỗi lệnh **tự khai** mức của nó ở một dòng `*Checkpoint: …*`
126
142
  > ngay dưới `## Gate` của chính nó — đọc dòng đó, đừng suy diễn. Bảng trên chỉ giải thích ba mức
127
143
  > **nghĩa là gì**.
@@ -188,7 +204,7 @@ Mỗi dòng ⚠️/🔴 phải ứng với một trạng thái **context-loader
188
204
  🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
189
205
 
190
206
 
191
- *Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID. Đọc `.feature` FE của UC (web/app), các màn Design Spec của nó, tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` (§4.5.6 của platform, nếu có — bảng này gộp mọi UC của platform, **lọc theo cột "Phục vụ SC" khớp SC của UC này** qua §10), và figma-components catalog cho `active_module`.*
207
+ *Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID. Đọc `.feature` FE của UC (web/app), các màn Design Spec của nó, tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` (§4.5.6 của platform, nếu có — bảng này gộp mọi UC của platform, **lọc theo cột "Serves SC" khớp SC của UC này** qua §10), và figma-components catalog cho `active_module`.*
192
208
 
193
209
  ## Context
194
210
  **BẮT BUỘC — đọc `.agent/steps/context-loader.md` và thực thi TOÀN BỘ quy trình trong đó**,
@@ -228,6 +244,47 @@ file tối thiểu) thì ghi tên component.
228
244
  - **Reused:** id được áp ở **usage site** (không bake vào component dùng chung) → gán theo cùng quy ước.
229
245
  - **Cross-platform:** nếu §4.5.6 của platform **kia** (block `web`/`app` trong cùng tech-doc gộp) đã có id cho cùng element logic, **dùng lại id value đó** (chỉ attribute khác theo platform) để web và app nhất quán và logic QC tái dùng được.
230
246
 
247
+ ### Bảng §4.5.6 ĐÃ CÓ id cho element này → **DÙNG LẠI AS-IS** *(G83)*
248
+
249
+ Đối xứng với luật *reverse-document* cho code ở gạch đầu tiên. Chỉ gán id mới cho element **chưa có
250
+ row**. Quy ước `{uc-lower}-{screen}-{element}-{type}` là **mặc định cho id MỚI** — **không** phải
251
+ chuẩn để chuẩn-hoá lại id đã có.
252
+
253
+ | Tình huống | Xử lý |
254
+ |---|---|
255
+ | Element **đã có row** trong §4.5.6 | **Giữ nguyên id**. Cập nhật cột `Element`/`Component`/`Action` nếu thật sự đổi; **không đụng cột Test-ID** |
256
+ | Element **chưa có row** | Gán theo quy ước, thêm row mới |
257
+ | Row trong bảng mà element **không còn** trong design-spec/BDD | **Không xoá** — nêu ở report để người quyết *(có thể đang phục vụ UC khác)* |
258
+
259
+ > **Vì sao as-is chứ không chuẩn hoá.** Bảng là **HỢP ĐỒNG**, không phải output của lệnh này. Chuẩn
260
+ > hoá một hợp đồng mà **cả FE lẫn QC đang bám vào**, chỉ vì tên không theo ý lệnh, là đổi hợp đồng
261
+ > **mà không ai yêu cầu** — rồi Step 5b trung thành hạ `qc_status` và bump revision cho một thứ chưa
262
+ > hỏng gì.
263
+ >
264
+ > **Đây là lỗ hổng lâu nhất của lệnh này** *(G83)*. Luật *"đã có test-id → dùng lại as-is"* vốn đã có
265
+ > ở gạch đầu — nhưng **chỉ cho CODE**. Vế cho BẢNG bị thiếu, trong khi bảng mới là hợp đồng còn code
266
+ > là bên phải tuân theo nó. Đo trên dự án thật: **28/28 tech-doc** có §4.5.6 **viết tay**, quy ước
267
+ > riêng (`uc{n}-z2-region` · `uc1-z2-rank-avatar / uc1-z2-rank-name`) mà lệnh này không tái tạo được.
268
+
269
+ ### `--force` — đổi tên hàng loạt *(ca hợp lệ, nhưng phải nói ra)*
270
+
271
+ Đổi convention toàn dự án là việc thật. Không có cờ → **DỪNG**:
272
+
273
+ ```
274
+ ❌ §4.5.6 của {TICKET-ID} ({platform}) đã có {n} id — giữ nguyên theo mặc định.
275
+ Muốn đặt lại tên toàn bộ theo quy ước framework: thêm --force
276
+ ⚠️ --force sẽ đổi {n} id mà FE đang gắn và QC đang bám:
277
+ · code FE trượt locator cho tới khi gắn lại (lint T17/T18 sẽ kêu)
278
+ · .Test.md bám id cũ (lint T19 sẽ kêu)
279
+ · qc_status của mọi SC liên quan → not_run (Step 5b)
280
+ ```
281
+
282
+ Có `--force` → report **bắt buộc** khai:
283
+ ```
284
+ ⚠️ --force: đã đổi {n} id hợp đồng — {danh sách id cũ → mới}
285
+ Chạy lại: /generate-code (FE gắn id mới) · /qc-design-test {UC-ID} (TC bám id mới)
286
+ ```
287
+
231
288
  ## Step 3 — Đảm bảo component tái dùng forward được test-id (catalog) *(chỉ `--from-code`)*
232
289
 
233
290
  Với mỗi component **reused** có action, tra section **`## Test-ID Forwarding`** của catalog (`{paths.domain_knowledge_dir}/figma-components/{active_module}.md`):
@@ -250,18 +307,18 @@ Tạo hoặc cập nhật §4.5.6 (block platform tương ứng) trong tech-doc
250
307
  - **(b) Bảng.** Cập nhật bảng §4.5.6 của platform này (thêm block §4.5 cho platform nếu chưa có).
251
308
  - Nếu **chưa** tồn tại (pure brownfield) → ghi một file tối thiểu: header `@trace` (gồm `@trace.testid_attr`) + §4.5.6. `/generate-tech-docs` điền các section còn lại sau; nó không được ghi đè các id §4.5.6 mà lệnh này đã ghi.
252
309
 
253
- > **Vì sao (a) lệch thì DỪNG chứ không ghi đè.** `@trace.testid_attr` là *tên thuộc tính* mà **mọi** locator QC của PRD này bám vào (`/qc-run-test` đọc nó để cấu hình `get_by_test_id`). Ghi đè sai một lần là làm **trượt toàn bộ** script của PRD — và test sẽ đỏ với `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. Lệch nghĩa là một trong hai đang sai: FE vừa đổi convention, hoặc `active_module` khai sai. Cả hai đều cần người nhìn, không đoán được từ đây.
310
+ > **Vì sao (a) lệch thì DỪNG chứ không ghi đè.** `@trace.testid_attr` là *tên thuộc tính* mà **mọi** locator QC của PRD này bám vào (`/qc-design-script` đọc nó để cấu hình `get_by_test_id`). Ghi đè sai một lần là làm **trượt toàn bộ** script của PRD — và test sẽ đỏ với `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. Lệch nghĩa là một trong hai đang sai: FE vừa đổi convention, hoặc `active_module` khai sai. Cả hai đều cần người nhìn, không đoán được từ đây.
254
311
 
255
312
  Mỗi row — **5 cột, đúng thứ tự của template** (`templates/tech-design.template.md` §4.5.6):
256
313
 
257
- `Test-ID | Element | Component | Action | Phục vụ SC (UC · SC)`
314
+ `Test-ID | Element | Component | Action | Serves SC (UC · SC)`
258
315
 
259
316
  - **Component** — trỏ `§4.5.1.x` nếu §4.5.1 đã vẽ; chưa có (ca brownfield ghi file tối thiểu) thì ghi tên component.
260
- - **Phục vụ SC** — danh sách `(UC · SC)` mà id này phục vụ. Một id phục vụ nhiều UC là **bình thường**: tiền tố UC trong tên id chỉ nói UC nào giới thiệu element đó đầu tiên.
317
+ - **Serves SC** — danh sách `(UC · SC)` mà id này phục vụ. Một id phục vụ nhiều UC là **bình thường**: tiền tố UC trong tên id chỉ nói UC nào giới thiệu element đó đầu tiên.
261
318
 
262
319
  > **KHÔNG ghi phân loại `reused`/`existing`/`new` vào bảng.** Nó là phân loại **lúc chạy** của Step 1 (dùng để rẽ nhánh Step 2–4), và nó **đổi theo thời gian** — một element `new` thành `existing` ngay khi dev viết code. Nhét dữ liệu biến thiên vào bảng hợp đồng là làm bảng sai dần mà không ai cập nhật.
263
320
  >
264
- > **Thứ tự cột là load-bearing:** `lint-trace` **T15** đọc cột "Phục vụ SC" theo **vị trí** (ô nội dung cuối cùng) để đối chiếu với `.feature`. Viết sai thứ tự là T15 đọc nhầm ô.
321
+ > **Thứ tự cột là load-bearing:** `lint-trace` **T15** đọc cột "Serves SC" theo **vị trí** (ô nội dung cuối cùng) để đối chiếu với `.feature`. Viết sai thứ tự là T15 đọc nhầm ô.
265
322
 
266
323
  ## Step 5b — Làm mất hiệu lực `qc_status` của SC bị ảnh hưởng *(chỉ khi ĐỔI id đã có)*
267
324
 
@@ -274,13 +331,33 @@ lực ≠ ghi đè"*: *"lệnh nào làm giá trị đó HẾT ĐÚNG thì BẮT
274
331
 
275
332
  ```
276
333
  với mỗi id ĐỔI:
277
- đọc cột "Phục vụ SC" của row đó → danh sách {UC-ID}-SC{N}
334
+ đọc cột "Serves SC" của row đó → danh sách {UC-ID}-SC{N}
278
335
  mở sổ {paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv
279
336
  với mỗi SC trong danh sách:
280
- qc_status → not_run (chỉ hạ từ `pass`/`fail`; đang `not_run`/`skip` thì để yên)
281
- qc_run_at → —
337
+ qc_status → not_run (chỉ hạ từ `pass`/`fail`; đang `not_run`/`skip` thì để yên)
338
+ qc_run_at → —
339
+ tech_doc_revision → @trace.revision MỚI của tech-doc ← bump, xem dưới
282
340
  ```
283
341
 
342
+ ### Bump `tech_doc_revision` — vì sao lệnh này cũng là một bumper *(G64)*
343
+
344
+ Tăng `@trace.revision` ở header tech-doc, rồi ghi số mới vào cột `tech_doc_revision` của **mọi row
345
+ trong các sổ vừa chạm**.
346
+
347
+ §4.5.6 là hợp đồng mà `/qc-design-test` **chép cứng giá trị id vào `.Test.md`** — một artifact **bền,
348
+ nằm lại**. Cơ chế phát hiện lỗi thời của tầng artifact QC (`steps/qc-stamp.md`) hoạt động theo **nhãn**:
349
+ `.Test.md` đóng dấu `tech_doc_revision`, trạm 4–5 so với hiện tại. **Sửa §4.5.6 mà không bump nhãn thì
350
+ cơ chế đó không nổ** — đúng ca quan trọng nhất.
351
+
352
+ > **Vì sao không dựa vào `Next` → `/review-tech-docs`.** Lệnh đó **có** bump (`:396` — set
353
+ > `tech_doc_revision` cho mọi row). Nhưng đường ấy chỉ đúng **khi người dùng đi theo `Next`**, mà
354
+ > Step 5b này tồn tại chính vì ca *"sửa nhanh một id rồi đi tiếp"*. Dựa vào `Next` là dựa vào **kỷ
355
+ > luật**, không phải vào máy — và `rules/workflow.md` gọi chỗ này là **điểm mù tuyệt đối**: *"mọi
356
+ > drift detector so **nhãn version**, không so **nội dung**"*. Không bump là tự tay đi vòng qua nhãn.
357
+ >
358
+ > **Thêm row MỚI thì KHÔNG bump** — cùng điều kiện với việc hạ `qc_status`: chưa `.Test.md` nào bám
359
+ > id mới, không gì hết đúng.
360
+
284
361
  **KHÔNG đụng `qc_owner` và `qc_blocked_by`.** `rules/workflow.md` miễn trừ tường minh hai cột
285
362
  này: chúng là **con trỏ tới bug**, và đổi một test-id không làm con bug biến mất. Xoá đi là mất
286
363
  đường về bug đang mở.
@@ -289,10 +366,16 @@ này: chúng là **con trỏ tới bug**, và đổi một test-id không làm c
289
366
 
290
367
  In ra ở report:
291
368
  ```
292
- ⚠️ {n} scenario có script QC bám id CŨ — qc_status hạ về not_run: {danh sách SC}
293
- Chạy /qc-design-test (hoặc /qc-run-test) lại cho các UC đó.
369
+ ⚠️ {n} scenario có TC/script QC bám id CŨ — qc_status hạ về not_run: {danh sách SC}
370
+ tech_doc_revision bump → {rev mới} (để .Test.md lỗi thời bị phát hiện ở trạm 4-5)
371
+ Chạy /qc-design-test lại cho các UC đó.
294
372
  ```
295
373
 
374
+ > **Chỉ `/qc-design-test`, KHÔNG phải "hoặc `/qc-design-script`"** *(G64 — lời nhắc cũ chỉ sai đường)*.
375
+ > `/qc-design-script` dựng locator từ §4.5.6 **tươi** nên phần locator nó tự cứu — nhưng nó **không sửa**
376
+ > id cũ đã nằm trong `.Test.md`. Ai chọn vế đó sẽ thấy test xanh trở lại và tưởng xong, trong khi tài
377
+ > liệu test vẫn mô tả một element không còn mang id đó.
378
+
296
379
  > **Vì sao hạ chứ không giữ.** `rules/workflow.md`: *"`pass` **không** mang nghĩa 'test đã chạy
297
380
  > xanh' — nó mang nghĩa 'scenario này đã được nghiệm thu theo spec **hiện tại**'."* Một script
298
381
  > định vị bằng id không còn tồn tại thì không nghiệm thu được gì cả. Và QC biết phải chạy lại
@@ -90,7 +90,7 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
90
90
 
91
91
  | Mức | Lệnh nào | `--yes` bỏ qua được? |
92
92
  |---|---|:---:|
93
- | **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
93
+ | **Không chặn** | `/review-code` · `/validate-traces` · `/debug` **KHÔNG phải vì read-only**: cả ba đều CÓ ghi file. Chúng không chặn vì thao tác ghi của chúng hoặc nằm sau một câu hỏi `(Y/N)`, hoặc nằm sau một cờ, hoặc là `append`/dựng-lại-được | — (vốn không có) |
94
94
  | **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
95
95
  | **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
96
96
 
@@ -98,6 +98,12 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
98
98
  `--` khỏi phần resolve target, nên cờ này không ảnh hưởng việc tìm file.) Mở đường chạy
99
99
  headless: `claude -p "/generate-code UC1 --yes"`.
100
100
 
101
+ > **Tên lệnh trong bảng trên có máy canh — `R19`.** Mỗi hàng bảng vừa nêu một mức vừa nêu
102
+ > tên lệnh sẽ bị đối chiếu với `gate.checkpoint_levels`; lệch là build đỏ. Lý do có rule này:
103
+ > ngày 2026-09-16 hai lệnh đổi mức, schema và `commands/*.tmpl` đều sửa, **build vẫn xanh**,
104
+ > mà bảng này lẫn `rules/workflow.md` đều còn liệt chúng ở mức cũ. `R11` chỉ canh
105
+ > `commands/*.tmpl` ↔ schema — *biết có máy canh không bằng biết máy canh **đến đâu***.
106
+
101
107
  > **KHÔNG tự suy mức từ bảng này.** Mỗi lệnh **tự khai** mức của nó ở một dòng `*Checkpoint: …*`
102
108
  > ngay dưới `## Gate` của chính nó — đọc dòng đó, đừng suy diễn. Bảng trên chỉ giải thích ba mức
103
109
  > **nghĩa là gì**.