@educa-corp/sdd-framework 0.4.2 → 0.6.0

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 (149) hide show
  1. package/bin/build.js +113 -19
  2. package/bin/gate-trace.js +464 -0
  3. package/bin/index.js +418 -146
  4. package/bin/lint-trace.js +602 -0
  5. package/bin/self-check.js +499 -6
  6. package/bin/trace-schema.json +1449 -692
  7. package/commands/debug.md +123 -510
  8. package/commands/debug.tmpl +3 -0
  9. package/commands/define-product.md +86 -509
  10. package/commands/dev-gen-test.md +120 -516
  11. package/commands/dev-run-test.md +120 -516
  12. package/commands/dev-smoke-test.md +86 -509
  13. package/commands/extend-prd.md +486 -0
  14. package/commands/extend-prd.tmpl +273 -0
  15. package/commands/fix-bug.md +152 -515
  16. package/commands/generate-architecture.md +94 -514
  17. package/commands/generate-architecture.tmpl +3 -0
  18. package/commands/generate-bdd.md +138 -519
  19. package/commands/generate-bdd.tmpl +18 -3
  20. package/commands/generate-code.md +156 -523
  21. package/commands/generate-code.tmpl +36 -7
  22. package/commands/generate-design-spec.md +86 -509
  23. package/commands/generate-prd.md +114 -509
  24. package/commands/generate-prd.tmpl +28 -0
  25. package/commands/generate-spec-manifest.md +86 -509
  26. package/commands/generate-tech-docs.md +86 -509
  27. package/commands/learn.md +172 -495
  28. package/commands/learn.tmpl +70 -3
  29. package/commands/map-testids.md +86 -509
  30. package/commands/propose-scenario.md +136 -508
  31. package/commands/propose-scenario.tmpl +52 -1
  32. package/commands/qc-analyze.md +86 -509
  33. package/commands/qc-design-test.md +87 -509
  34. package/commands/qc-design-test.tmpl +1 -0
  35. package/commands/qc-plan.md +86 -509
  36. package/commands/qc-report.md +86 -509
  37. package/commands/qc-review.md +86 -509
  38. package/commands/qc-run-test.md +133 -517
  39. package/commands/qc-run-test.tmpl +13 -1
  40. package/commands/refine-prd.md +99 -519
  41. package/commands/refine-prd.tmpl +3 -0
  42. package/commands/report-bug.md +86 -509
  43. package/commands/review-code.md +127 -513
  44. package/commands/review-code.tmpl +7 -3
  45. package/commands/review-context.md +96 -515
  46. package/commands/review-context.tmpl +6 -2
  47. package/commands/review-tech-docs.md +90 -510
  48. package/commands/review-tech-docs.tmpl +3 -0
  49. package/commands/setup-ai-first.md +166 -137
  50. package/commands/setup-ai-first.tmpl +72 -0
  51. package/commands/sync.md +86 -118
  52. package/commands/sync.tmpl +84 -16
  53. package/commands/update-framework.md +16 -102
  54. package/commands/update-framework.tmpl +14 -0
  55. package/commands/validate-traces.md +458 -531
  56. package/commands/validate-traces.tmpl +381 -31
  57. package/core/FRAMEWORK_VERSION +1 -1
  58. package/core/README.md +20 -0
  59. package/core/commands/debug.md +123 -510
  60. package/core/commands/define-product.md +86 -509
  61. package/core/commands/dev-gen-test.md +120 -516
  62. package/core/commands/dev-run-test.md +120 -516
  63. package/core/commands/dev-smoke-test.md +86 -509
  64. package/core/commands/extend-prd.md +486 -0
  65. package/core/commands/fix-bug.md +152 -515
  66. package/core/commands/generate-architecture.md +94 -514
  67. package/core/commands/generate-bdd.md +138 -519
  68. package/core/commands/generate-code.md +156 -523
  69. package/core/commands/generate-design-spec.md +86 -509
  70. package/core/commands/generate-prd.md +114 -509
  71. package/core/commands/generate-spec-manifest.md +86 -509
  72. package/core/commands/generate-tech-docs.md +86 -509
  73. package/core/commands/learn.md +172 -495
  74. package/core/commands/map-testids.md +86 -509
  75. package/core/commands/propose-scenario.md +136 -508
  76. package/core/commands/qc-analyze.md +86 -509
  77. package/core/commands/qc-design-test.md +87 -509
  78. package/core/commands/qc-plan.md +86 -509
  79. package/core/commands/qc-report.md +86 -509
  80. package/core/commands/qc-review.md +86 -509
  81. package/core/commands/qc-run-test.md +133 -517
  82. package/core/commands/refine-prd.md +99 -519
  83. package/core/commands/report-bug.md +86 -509
  84. package/core/commands/review-code.md +127 -513
  85. package/core/commands/review-context.md +96 -515
  86. package/core/commands/review-tech-docs.md +90 -510
  87. package/core/commands/setup-ai-first.md +166 -137
  88. package/core/commands/sync.md +86 -118
  89. package/core/commands/update-framework.md +16 -102
  90. package/core/commands/validate-traces.md +458 -531
  91. package/core/hooks/data-guard.js +174 -83
  92. package/core/hooks/settings.json +2 -1
  93. package/core/rules/workflow.md +48 -4
  94. package/core/steps/capture-lesson.md +34 -1
  95. package/core/steps/context-loader.md +24 -3
  96. package/core/steps/gate.md +92 -35
  97. package/core/steps/report-footer.md +26 -2
  98. package/core/steps/trace-mirror.md +34 -7
  99. package/core/templates/README.md +24 -1
  100. package/core/templates/ci/trace-gate.yml +146 -0
  101. package/core/templates/feature.template +1 -1
  102. package/core/templates/hooks/pre-push +61 -0
  103. package/docs/01-getting-started/installation.md +18 -1
  104. package/docs/01-getting-started/what-is-sdd.md +4 -2
  105. package/docs/02-concepts/architecture.md +48 -5
  106. package/docs/02-concepts/pipeline-steps/02-specification.md +39 -3
  107. package/docs/02-concepts/pipeline-steps/04-bdd.md +24 -2
  108. package/docs/02-concepts/pipeline-steps/05-tech-docs.md +18 -1
  109. package/docs/02-concepts/pipeline-steps/06-code.md +35 -4
  110. package/docs/02-concepts/pipeline-steps/09-validate-traces.md +137 -12
  111. package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +59 -3
  112. package/docs/02-concepts/roles-and-hitl.md +1 -1
  113. package/docs/02-concepts/traceability.md +183 -117
  114. package/docs/03-guides/architect.md +63 -0
  115. package/docs/03-guides/developer.md +20 -4
  116. package/docs/03-guides/product-owner.md +72 -68
  117. package/docs/03-guides/tester-qa.md +81 -70
  118. package/docs/04-reference/commands.md +134 -105
  119. package/docs/04-reference/configuration.md +146 -94
  120. package/docs/04-reference/model-selection.md +32 -19
  121. package/docs/04-reference/trace-schema.md +26 -9
  122. package/docs/explain/02-generate-prd.md +80 -78
  123. package/docs/explain/02b-extend-prd.md +125 -0
  124. package/docs/explain/03-refine-prd.md +86 -86
  125. package/docs/explain/04-review-context.md +18 -1
  126. package/docs/explain/06-generate-bdd.md +23 -0
  127. package/docs/explain/08-review-tech-docs.md +20 -5
  128. package/docs/explain/10-review-code.md +36 -2
  129. package/docs/explain/19-qc-run-test.md +87 -67
  130. package/docs/explain/21-validate-traces.md +75 -68
  131. package/docs/explain/23-fix-bug.md +19 -3
  132. package/docs/explain/26-propose-scenario.md +70 -63
  133. package/docs/explain/27-learn.md +5 -3
  134. package/docs/explain/README.md +135 -134
  135. package/hooks/data-guard.js +174 -83
  136. package/hooks/settings.json +2 -1
  137. package/package.json +53 -50
  138. package/rules/workflow.md +48 -4
  139. package/steps/capture-lesson.md +34 -1
  140. package/steps/context-loader.md +24 -3
  141. package/steps/gate.md +92 -35
  142. package/steps/report-footer.md +26 -2
  143. package/steps/trace-mirror.md +34 -7
  144. package/templates/README.md +24 -1
  145. package/templates/ci/trace-gate.yml +146 -0
  146. package/templates/feature.template +1 -1
  147. package/templates/hooks/pre-push +61 -0
  148. package/scripts/init.sh +0 -49
  149. package/scripts/upgrade.sh +0 -94
@@ -61,14 +61,57 @@ Spec-driven thành/bại phụ thuộc **~80%** vào việc context được n
61
61
  ## Template Pipeline
62
62
 
63
63
  ```
64
- .tmpl (source) + steps/*.md --[node bin/build.js, {{include:...}}]--> commands/*.md + core/
65
-
66
-
67
- .agent/commands/*.md (runtime)
64
+ .tmpl + steps/*.md ──build──► commands/*.md ──► core/* ──► .agent/ 904 KB
65
+
66
+ bin/self-check.js (fail build) --init cài vào đây
68
67
  ```
69
68
 
70
- - chế `{{include:steps/...}}` ghép phẳng single source of truth `.tmpl` + `steps/`.
69
+ **Vì sao slim (G45):** build inline `{{include:}}` vào **từng** file lệnh. Với 32 lệnh, kết quả
70
+ 2069 KB mà chỉ 580 KB là nội dung riêng của chúng — **72% là vài step giống hệt nhau, chép 30 lần**.
71
+ `/generate-code` từng nặng 108 KB (≈27k token đọc **trước** khi làm gì), gần một nửa không nói gì về
72
+ việc sinh code. Cái giá thật không phải tiền: trên PRD nhiều UC nó làm tăng rủi ro **cạn context
73
+ giữa lúc ghi sổ trace**.
74
+
75
+ | Step | Xử lý trong `core/` | Vì sao |
76
+ |---|---|---|
77
+ | `context-loader.md` (33 K × 29) | **đọc lúc chạy** | 64% lãng phí. Bỏ sót ⇒ lệnh **dừng ngay** vì thiếu path/config — hỏng ồn ào |
78
+ | `report-footer.md` (7 K × 32) | **đọc lúc chạy** | 16%. Bỏ sót ⇒ report kém cấu trúc, không hỏng gì |
79
+ | `gate.md` (7 K × 30) | **giữ inline** | Chỉ 15%, nhưng là **lưới an toàn** (model check · resolve target · CHECKPOINT). Bỏ sót ⇒ lệnh **vẫn chạy** mà không còn cổng nào — hỏng **âm thầm** |
80
+
81
+ Kết quả: `/generate-code` 108 KB → **69 KB**, `/refine-prd` 85 KB → **45 KB**.
82
+
83
+ > **Một biến thể duy nhất.** Bản đầu của G45 phải build **hai** bản: `commands/*.md` inline đầy đủ
84
+ > cho legacy mode (`--project` / không cờ) — vì nó copy thẳng file đó vào `.claude/commands/` mà
85
+ > **không** cài `.agent/`, nên không có `.agent/steps/` để đọc — và bản slim cho `--init`.
86
+ > **G50 gỡ hẳn legacy mode**, nên giờ mọi bản cài đều có `.agent/steps/` và nhánh build thứ hai
87
+ > biến mất. Hai nhánh build gần giống nhau là nợ chờ lệch.
88
+
89
+ - Cơ chế `{{include:steps/...}}` → single source of truth ở `.tmpl` + `steps/`.
71
90
  - **Không sửa tay** `commands/*.md` / `.agent/` — sửa `.tmpl`/`steps` rồi `node bin/build.js`. *(Quy ước + memory bảo vệ, không phải hook.)*
91
+ - **Sửa `steps/context-loader.md` hay `report-footer.md` giờ có hiệu lực NGAY** ở project đã cài — chúng được đọc lúc chạy, không còn phải build + publish + `/update-framework`.
92
+ - **Template artifact cũng bị inline lúc build.** `templates/feature.template` và `prd.template.md` được `{{include}}` **nướng cứng** vào file lệnh, nên lệnh không đọc path template lúc chạy — sửa `.agent/templates/` **không có tác dụng**. Đổi cấu trúc `.feature`/PRD = sửa `templates/*` trong repo framework rồi build lại.
93
+
94
+ ### Self-check — contract trace không được lệch
95
+
96
+ ```
97
+ bin/trace-schema.json ──[bin/self-check.js]──> đối chiếu commands/*.tmpl + steps/*.md
98
+ (SoT máy đọc) → exit 1 nếu lệch → build FAIL
99
+ ```
100
+
101
+ **Vì sao cần:** phần lớn lỗi lịch sử của framework là **cùng một dạng** — contract (field `@trace.*`, cột `.tsv`, path pattern, giá trị enum) được phát biểu lại bằng **prose** ở nhiều lệnh rồi lệch nhau qua từng lần sửa, và không có gì phát hiện. Ca thuần khiết nhất: `@trace.sc_version` từng có **3 consumer, 0 producer** — nghĩa là `DRIFT` chết hoàn toàn — mà không lệnh nào, cổng nào, test nào bắt được.
102
+
103
+ | Rule | Bắt gì | Mức |
104
+ |:---:|---|:---:|
105
+ | R1 | field có consumer nhưng **không producer** | ERROR |
106
+ | R2 | field có producer nhưng **không ai đọc** (field chết) | WARN |
107
+ | R3 | actor khai trong schema mà file của nó **không nhắc** field | ERROR |
108
+ | R4 | `{paths.X}` dùng mà không khai / khai mà không ai dùng | ERROR / WARN |
109
+ | R5 | pattern bị cấm **quay lại** (vd `bdd/` thiếu `{platform}`) | ERROR |
110
+ | R6 | giá trị enum khai mà **không xuất hiện ở đâu** | WARN |
111
+
112
+ **Quy tắc vận hành:** đổi contract → sửa `bin/trace-schema.json` **TRƯỚC**, rồi mới sửa lệnh, rồi cập nhật [Trace Schema (người đọc)](../04-reference/trace-schema.md). Chạy riêng: `npm run self-check`.
113
+
114
+ *(Schema là JSON chứ không YAML vì `package.json` có **zero dependency** — npx chạy không cần install; thêm `js-yaml` chỉ để đọc một file build-time là không đáng. Nó nằm ở `bin/` chứ không `templates/` để không lọt vào `.agent/templates/` của mọi project.)*
72
115
 
73
116
  ---
74
117
 
@@ -3,7 +3,17 @@
3
3
  # Bước 2 · Specification — Hình thành đặc tả (PRD)
4
4
 
5
5
  > **Tóm tắt.** Biến khung intent thành **PRD** chuẩn nghiệp vụ, tinh chỉnh qua 3 lăng kính, rồi qua **gate chất lượng** để PO đóng dấu `approved`.
6
- > **Commands:** `/generate-prd` → `/refine-prd` → `/review-context`
6
+ > **Commands:** `/generate-prd` (lần đầu) · `/extend-prd` (thêm vào PRD đã có) → `/refine-prd` → `/review-context`
7
+
8
+ > **Chọn lệnh nào — PRD mới vs PRD đã có:**
9
+ >
10
+ > | Tình huống | Lệnh | Vì sao không dùng cái kia |
11
+ > |---|---|---|
12
+ > | PRD **chưa tồn tại** | `/generate-prd` | — |
13
+ > | PRD đã có, **thêm** UC/AC/BR mới | **`/extend-prd`** | `/generate-prd` **từ chối chạy** trên file đã có |
14
+ > | PRD đã có, **sửa vấn đề** đã soi ra | `/refine-prd` → Review Board → `--resume` | `/refine-prd` **không thêm được** yêu cầu mới — nó tự cấm đụng section ngoài findings |
15
+ >
16
+ > **`/generate-prd` dừng hẳn (không hỏi Y/N) nếu file đã tồn tại.** Ghi đè sẽ mất `# Change Log` + rollover, Version/Status thật, và **đánh số lại BR từ đầu** — cái cuối lan **ra ngoài file**, phá mọi `@trace.business_rules` trong `bdd/` đã sinh. Ba mất mát đều không hoàn tác được từ trong lệnh, nên không đặt sau một phím bấm.
7
17
 
8
18
  | | |
9
19
  |---|---|
@@ -29,7 +39,8 @@ PRD là **hợp đồng nghiệp vụ** giữa PO ↔ Dev ↔ AI. Đây là **c
29
39
 
30
40
  | Lệnh | Vai trò | Kết quả |
31
41
  |------|---------|---------|
32
- | `/generate-prd` | **Sinh** PRD draft từ product-definition | PRD `Status: draft` |
42
+ | `/generate-prd` | **Sinh** PRD draft từ product-definition. Từ chối chạy nếu PRD đã tồn tại | PRD `Status: draft` |
43
+ | `/extend-prd` | **Thêm** UC/AC/BR vào PRD đã duyệt — đánh số **nối tiếp**, ghi **add-only** + guard sau-ghi, drain `feedback/prd-change-requests/` | PRD v+1, `Status → draft` |
33
44
  | `/refine-prd` | **Tinh chỉnh** qua 3 lăng kính DEV/SA/PO (fan-out per-UC) | Findings để PO accept/reject |
34
45
  | `/review-context` | **Gate chất lượng** — findings P0–P5, phải sạch critical | PO đặt `Status: approved` |
35
46
 
@@ -73,7 +84,32 @@ PRD là **hợp đồng nghiệp vụ** giữa PO ↔ Dev ↔ AI. Đây là **c
73
84
 
74
85
  ## Framework xử lý thế nào (Mechanics)
75
86
 
76
- **`/generate-prd`** — Round Q&A + confirm domain/terminology → sinh PRD draft đúng template, áp Business Language Guard.
87
+ **`/generate-prd`** — Round Q&A + confirm domain/terminology → sinh PRD draft đúng template, áp Business Language Guard. **Guard đầu vào:** file đã tồn tại → dừng hẳn, chỉ sang `/extend-prd`.
88
+
89
+ **`/extend-prd`** — 7 bước, tái dùng tối đa thứ đã có:
90
+
91
+ 1. Nạp trạng thái: `max_uc` / `max_br` / `max_ac`, UC hiện có, changelog, BDD đã sinh cho những UC nào
92
+ 2. **Drain hàng đợi** `prd-change-requests/` — `accepted` → nguyên liệu; `Open` → trình PO kèm số ngày chờ
93
+ 3. Discovery delta — tái dùng Phase 1/4/5/6 của `/define-product` (bỏ Phase 0/2/7 vốn là toàn-feature), **cộng phase "kiểm va chạm"**
94
+ 4. **Đánh số nối tiếp** — ràng buộc cứng nhất
95
+ 5. Ghi **Edit add-only** + guard sau-ghi
96
+ 6. Bump version + changelog — tái dùng **nguyên** `/refine-prd` Phase 3
97
+ 7. Report: nêu rõ **UC không đổi** + route `--realign-prd-version` cho chúng
98
+
99
+ **Phase "kiểm va chạm" — `/define-product` không có.** Lúc discovery lần đầu chưa có gì để va chạm; ở đây thì có. Ba câu bắt buộc:
100
+
101
+ | Câu | Vì sao |
102
+ |---|---|
103
+ | Phần thêm làm một BR cũ **sai đi** không? | *(BR cũ "tối đa 5", phần mới cần 20)* → đây là **sửa** BR cũ, không phải thêm mới → bump **major** |
104
+ | Đã có UC/AC nào **phủ một phần** chưa? | → hỏi PO: mở rộng UC cũ hay tạo mới. **Không tự quyết** |
105
+ | Cần dữ liệu/năng lực từ đâu khác? | → ghi vào §1c Phụ thuộc liên service |
106
+
107
+ Va chạm âm thầm là cách một PRD **tự mâu thuẫn với chính nó**.
108
+
109
+ **Hai ràng buộc cứng:**
110
+
111
+ - **Không đánh lại BẤT KỲ ID cũ nào.** UC/AC/BR mới đều là `max + 1`. Số bị bỏ trống (do UC bị xoá ở version trước) **để trống vĩnh viễn** — ID đã từng tồn tại có thể còn bị tham chiếu ở BDD, code, bug report, hoặc PRD khác.
112
+ - **Dòng changelog phải nêu rõ UC/AC/BR.** Đây là **contract**: `/generate-bdd` đọc để quyết cập nhật hẹp (Y) hay gen lại toàn bộ (F), và `/validate-traces` Step 4/5 đọc để lọc `PRD_DRIFT` 🟠 vs `PRD_STALE_REF` ⓘ. Một dòng mơ hồ (`"cập nhật theo yêu cầu mới"`) làm **mất cả hai** bộ lọc cùng lúc.
77
113
 
78
114
  **`/refine-prd`** — fan-out **mỗi UC × 3 lăng kính**:
79
115
  - **DEV** — chỗ nào khó hiện thực / thiếu định nghĩa?
@@ -36,9 +36,14 @@ BDD là **trái tim của traceability**. Mỗi scenario là một đơn vị h
36
36
  | Artifact | Nội dung |
37
37
  |----------|----------|
38
38
  | `specs/{domain}/{prd-slug}/bdd/{web\|app\|system}/{UC-ID}*.feature` | Scenario Gherkin + tag `@trace.*` + Coverage Matrix |
39
+ | `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` | Sổ trace — **một sổ cho mỗi UC × platform** |
39
40
  | `@trace.status: approved` (sau review) | 🔒 Mở khoá `/generate-tech-docs` |
40
41
 
41
- > BDD chia theo **platform/scope**: `web/`, `app/`, `system/` (cross-service).
42
+ > **Subfolder `{platform}/` LUÔN — mọi mode, kể cả umbrella.** `web` `system` của cùng một UC là **hai file khác nhau**; bỏ subfolder thì chúng ra cùng filename và **ghi đè nhau**. Trace cũng tách theo platform, nên bố cục spec phải khớp. Mỗi `.feature` còn mang `@trace.platform` **khớp** segment path của chính nó.
43
+ >
44
+ > Ở umbrella mode, `active_platform` được **suy từ `active_module`** (react/vue/… → `web` · flutter/RN/… → `app` · java-spring/golang/… → `system`); không suy được thì lệnh **dừng và hỏi**, không ghi file.
45
+ >
46
+ > *Project còn ở bố cục phẳng cũ (`bdd/*.feature`): chạy `npx @educa-corp/sdd-framework --migrate-bdd-platform` — dry-run mặc định.*
42
47
 
43
48
  ---
44
49
 
@@ -68,7 +73,24 @@ BDD là **trái tim của traceability**. Mỗi scenario là một đơn vị h
68
73
  2. 🛑 **UC decomposition checkpoint** — trình danh sách UC/SC để PO chốt.
69
74
  3. PRD lớn → **fan-out**: orchestrator giao mỗi UC cho một sub-agent (`_agent_mode`) sinh song song.
70
75
  4. Sinh `.feature` theo `feature.template`, gắn `@trace.*`, dựng Coverage Matrix.
71
- 5. thể incorporate **scenario proposal** đã `accepted` từ tester (xem [Feedback Loop](10-feedback-loop.md)).
76
+ 5. **Gen lại:** bump `@trace.sc_version` **+0.1 cho từng SC có thân đổi** (xem dưới); SC bị xoá mà **đã có code** giữ row `.tsv`, đặt `status = ORPHANED` (không xoá row — xoá đi thì code thành vô hình).
77
+ 6. Có thể incorporate **scenario proposal** đã `accepted` từ tester — khi chèn phải **normalize**: gán `sc_id` kế tiếp, strip `@proposed`/`@from-test`, append row `.tsv` (xem [Feedback Loop](10-feedback-loop.md)).
78
+
79
+ ### `sc_version` — tín hiệu DRIFT duy nhất
80
+
81
+ Mỗi scenario mang `@trace.sc_version` riêng. Nó là **thứ duy nhất** cho `/validate-traces` biết code của SC đó đã lỗi thời (`spec_ver != gen_ver` → `DRIFT`).
82
+
83
+ | Đổi cái gì | Bump? |
84
+ |---|:---:|
85
+ | Tên `Scenario:` · chuỗi step · data table · `# Side-effects:` | ✅ **+0.1** |
86
+ | `@trace.business_rules` · tag `@happy`/`@edge` · comment | ❌ không |
87
+ | Header file · Coverage Matrix · gom NHÓM | ❌ không (đó là `bdd_version`) |
88
+
89
+ **Ai bump:** `/generate-bdd` (khi gen lại, so 4 thành phần trên với bản trên disk) · `/review-context --fix`/`--resume` (mỗi SC có finding đổi thân) · **người sửa tay** (có mục trong Pre-merge Checklist).
90
+
91
+ > Sửa SC mà quên bump → code sinh từ bản cũ **vĩnh viễn hiện `OK`**, không ai biết phải regen. Bump vô cớ thì ngược lại: mọi SC hiện `DRIFT` giả và cờ mất giá trị.
92
+ >
93
+ > Phân biệt với `@trace.bdd_version` (**cấp file**): nó bắt thay đổi mà `sc_version` không thấy — Background, `@trace.dataset`, Business Definition. Cả hai đều cần.
72
94
 
73
95
  **`/review-context` (BDD)** — findings có mã, sạch critical mới `approved`:
74
96
 
@@ -74,15 +74,32 @@
74
74
 
75
75
  **`/review-tech-docs`** — review **đa chiều**, findings gom theo từng UC (đọc §10 UC Coverage):
76
76
  - Kiểm tính đủ/đúng của contract, entity, error, dependency.
77
+ - **T3 — BDD traceability**: design có khớp **nội dung** scenario không (2 chiều, match trong đúng lane platform).
78
+ - **T3b — BDD freshness**: doc này dựng từ BDD **version nào**, BDD giờ ở version nào.
77
79
  - **T7 — cổng ký liên team**: contract cross-service phải được các team liên quan **ký** trước khi code.
78
80
 
81
+ ### T3b — vì sao độ tươi cần một cổng riêng
82
+
83
+ Header tech-doc mang `@trace.bdd_versions` — **map theo platform** (`system=1.5, web=1.9`), số nhiều, cố ý khác `@trace.bdd_version` (scalar) của `.feature`. T3b so từng entry với `.feature` tương ứng:
84
+
85
+ | Điều kiện | Severity | Auto-fix? |
86
+ |---|---|---|
87
+ | `.feature` **mới hơn** map | **Major** | ❌ cần người review lại §4/§4.5 rồi bump `@trace.revision` |
88
+ | Platform có `.feature` nhưng **vắng** trong map | Major | ✅ thêm entry sau khi xác nhận §4 đã phủ |
89
+ | Map có platform mà không còn `.feature` | Minor | ✅ xoá entry |
90
+
91
+ > **Major chứ không Minor** vì `/generate-code` DS3 thấy doc `approved` + 0 blocker-GAP sẽ lấy shape DTO/endpoint/error ở §4 **nguyên văn**. Contract dựng từ BDD cũ lan **thẳng** vào code — tệ hơn drift-về-code vì nó sai từ nguồn.
92
+ >
93
+ > Khi áp fix, **cấm chỉ sửa số trong map** cho ca "`.feature` mới hơn": làm thế là dán nhãn "đã đồng bộ" lên một contract chưa ai review. Platform còn finding `open` thì **giữ số cũ** để cờ `TECHDOC_STALE_VS_BDD` của [`/validate-traces`](09-validate-traces.md) còn sáng.
94
+
79
95
  ---
80
96
 
81
97
  ## HITL / Gate
82
98
 
83
99
  - 🟠 SA duyệt tech-design; **read-only** review — chỉ báo findings, không tự sửa.
84
100
  - 🔒 **T7 sign-off**: contract liên team chưa ký → không mở khoá code phía tiêu thụ.
85
- - `@trace.status: approved` trên tech-design `/generate-code` dùng §4 làm nguồn contract; `draft/in-review` hoặc còn blocker-GAP chỉ WARN (không chặn).
101
+ - 🟡 **T3b (chặn mềm)**: còn finding T3b Major `open` CHECKPOINT `Y/N` trước khi đặt `approved`. Mềm chứ không cứng như GATE §12 blocker-GAP, BDD hay bump vì lý do **không chạm contract** (sửa từ ngữ step) — người review là người biết.
102
+ - `@trace.status: approved` trên tech-design → `/generate-code` dùng §4 làm nguồn contract; `draft/in-review` hoặc còn blocker-GAP → chỉ WARN (không chặn). Tech-doc **cũ hơn BDD** cũng chỉ WARN — nhưng là WARN quan trọng nhất, vì nó xuất hiện đúng lúc shape §4 được lấy nguyên văn.
86
103
 
87
104
  ---
88
105
 
@@ -37,8 +37,28 @@ Code là **hệ quả của spec, không phải nguồn**. Bước này biến s
37
37
 
38
38
  | Artifact | Nội dung |
39
39
  |----------|----------|
40
- | File code | Theo thứ tự layer của stack, tag `@trace.implements/source` ở boundary |
41
- | `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` | Trace row cập nhật: `status`, `implemented_by`, `bdd_version`… |
40
+ | File code | Theo thứ tự layer của stack, **block 5 tag** ở boundary (dưới) |
41
+ | `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` | Trace row cập nhật: `status`, `implemented_by`, `gen_ver`, `fe_phase`… |
42
+ | `_seams.tsv` | Sổ nợ seam/stub — chỗ chưa implement, để không đẻ mồ côi |
43
+
44
+ ### Block 5 tag trên mỗi entry-point
45
+
46
+ ```java
47
+ // @trace.implements=AUTH-UC1-SC3
48
+ // @trace.prd_version=1.2
49
+ // @trace.bdd_version=1.4
50
+ // @trace.tech_doc_revision=3
51
+ // @trace.source=specs/auth/login/bdd/system/AUTH-UC1-login.feature
52
+ public TokenDto login(...) { }
53
+ ```
54
+
55
+ 3 tag version không phải trang trí — chúng là nguồn của `PRD_DRIFT` / `BDD_DRIFT` / `TECHDOC_DRIFT` ở [`/validate-traces`](09-validate-traces.md). Thiếu một tag = drift detection **mù ở file đó**, im lặng.
56
+
57
+ > **File phủ nhiều UC → lặp CẢ BLOCK theo từng method.** Không gộp về một header file, không trỏ `@trace.source` vào **thư mục**.
58
+ >
59
+ > Vì sao: 3 tag version là scalar **theo từng UC** — gộp lại thì không diễn đạt được "UC1 ở bdd v1.4, UC3 ở v2.1" → drift báo oan hoặc mù. Và các lệnh tra tag bằng **khớp chuỗi chính xác** (`/dev-gen-test`, `/review-code`, `/validate-traces` đều tìm `@trace.implements={UC-ID}`), nên tag trỏ thư mục ra **0 kết quả** → UC rơi về `UNTRACKED` dù code đã có.
60
+ >
61
+ > Quy tắc EXTEND vốn đã yêu cầu giữ **nguyên si** mọi `@trace.implements` cũ *kể cả của UC khác* — tức thiết kế vốn là **tích luỹ nhiều block**.
42
62
 
43
63
  ---
44
64
 
@@ -80,8 +100,19 @@ Code là **hệ quả của spec, không phải nguồn**. Bước này biến s
80
100
 
81
101
  > Nhánh wire API thật (`integration` / `fe_full`) đi qua **DS4** (kiểm §4.5.4 đủ, vét nguồn rồi gộp-hỏi) và **DS5** (phát hiện component/service FE đang chạy → hỏi reuse/new, không dựng song song). Bảng hành vi đầy đủ từng bước → [Explain · generate-code](../../explain/09-generate-code.md#hành-vi-theo-mode-phase--platform).
82
102
 
83
- **`/review-code`** — read-only, chỉ báo findings (không tự sửa: "AI tự fix tự review" = lặp lỗi).
84
- **`/fix-bug`** — sửa lỗi có root-cause + regression test; xem [Feedback Loop](10-feedback-loop.md).
103
+ **`/review-code`** — read-only, chỉ báo findings (không tự sửa: "AI tự fix tự review" = lặp lỗi). **5 lăng kính:**
104
+
105
+ | # | Lăng kính | Điểm đáng chú ý |
106
+ |---|---|---|
107
+ | 1 | Traceability | đủ **4 tag version** kèm mỗi `@trace.implements` · `@trace.source` trỏ file **có thật, đúng platform** · file đa-UC có block riêng theo method · **tag mồ côi** (`TRACE_ORPHAN`) = critical |
108
+ | 2 | Layer Architecture | đúng layer, chiều phụ thuộc, không bypass |
109
+ | 3 | Coding Standards | naming, wrapper, exception, transaction, không magic number |
110
+ | 4 | Spec Compliance | mỗi scenario có implementation, không endpoint không-spec |
111
+ | 5 | **Seam & Stub** | sổ `_seams.tsv` 0 dòng `READY` · stub không còn là binding khi hàng thật đã có · **method thật mồ côi** do đẻ song song |
112
+
113
+ > Critical ở lăng kính 5 → `NEEDS_FIX` **kể cả khi build xanh và test từng-UC xanh** — đó chính là lớp lỗi hai thứ đó không bắt được.
114
+
115
+ **`/fix-bug`** — sửa lỗi có root-cause + regression test, **và cập nhật sổ trace**; xem [Feedback Loop](10-feedback-loop.md).
85
116
 
86
117
  ---
87
118
 
@@ -2,8 +2,10 @@
2
2
 
3
3
  # Bước 9 · Validate Traces — Ma trận độ phủ (Coverage Matrix)
4
4
 
5
- > **Tóm tắt.** Check **read-only** độ phủ giữa **spec ↔ code ↔ test**, gồm cả PRD version drift. Chỉ ra chỗ chưa phủ — không sửa gì.
6
- > **Command:** `/validate-traces`
5
+ > **Tóm tắt.** Check độ phủ giữa **spec ↔ code ↔ test** 2 chiều quét, **6 tầng drift**, 4 cờ 🔴 chặn PR, 2 cờ ⓘ. Chỉ ra chỗ chưa phủ — mặc định **không sửa gì**.
6
+ > **Command:** `/validate-traces` · `--realign-prd-version {UC-ID}` · `--realign-techdoc-revision {UC-ID}`
7
+ >
8
+ > *Lệnh **read-only** ở chế độ thường. Hai flag `--realign-*` là ngoại lệ có kiểm soát: chúng sửa **đúng dòng `@trace.*`** trong code, không đụng logic — xem [Realign](#realign--đường-ra-cho-cờ-ⓘ).*
7
9
 
8
10
  | | |
9
11
  |---|---|
@@ -19,8 +21,10 @@
19
21
 
20
22
  Traceability chỉ có giá trị khi **kiểm được**. Bước này cho một **bức tranh toàn cục**: scenario nào đã có code, có test, hay còn hở — để không "tưởng xong mà chưa xong". Vì là **read-only**, chạy lúc nào cũng an toàn.
21
23
 
22
- - Đối chiếu spec ↔ code ↔ test cho từng SC.
23
- - Phát hiện **PRD version drift** (spec đổi code chưa regen).
24
+ - Đối chiếu spec ↔ code ↔ test cho từng SC (chiều **spec → code**).
25
+ - Quét **chiều ngược** (code spec): tag trỏ vào scenario **không còn tồn tại**.
26
+ - Phát hiện drift ở **4 tầng**: PRD · BDD · tech-doc → code, và tech-doc lỗi thời so với BDD.
27
+ - Bắt **mồ côi khi ghép luồng** (seam/stub) — lớp lỗi mà build xanh + test từng-UC xanh không thấy.
24
28
  - Chỉ ra **gap** chưa phủ để lên kế hoạch bù.
25
29
 
26
30
  ---
@@ -35,7 +39,10 @@ Traceability chỉ có giá trị khi **kiểm được**. Bước này cho mộ
35
39
  | Artifact | Nội dung |
36
40
  |----------|----------|
37
41
  | Ma trận coverage spec ↔ code ↔ test | Trạng thái từng SC + `code_coverage` tổng |
38
- | (Tuỳ chọn) `trace-report.md` | Báo cáo tổng hợp |
42
+ | `{trace_dir}/trace-report.json` | Bản máy đọc cho **panel VS Code** ("Spec Driven Docs Tools") — bị **ghi đè** mỗi lần chạy |
43
+ | `{trace_dir}/trace-history.jsonl` | **Nhật ký append-only** — mỗi lần chạy ghi thêm 1 dòng *delta*. Đây là **dữ liệu**, không phải mirror: **phải commit**, mất là mất vĩnh viễn |
44
+ | Cờ audit | 6 cờ drift + 4 cờ 🔴 chặn PR + 2 cờ ⓘ (bảng dưới) |
45
+ | Hàng đợi | Đếm PRD change request còn `Open` kèm **số ngày chờ** (Step 7b) |
39
46
 
40
47
  ---
41
48
 
@@ -52,23 +59,124 @@ Traceability chỉ có giá trị khi **kiểm được**. Bước này cho mộ
52
59
 
53
60
  - Scenario nào **chưa có code** (UNTRACKED)? Chưa có test (GAP)?
54
61
  - Code nào **lỗi thời** so với spec (DRIFT)?
62
+ - Có code nào đang trỏ vào **scenario đã bị xoá** (ORPHANED / TRACE_ORPHAN)?
63
+ - Màn FE nào **demo được nhưng chưa nối backend** (`fe_phase = ui`)?
64
+ - Luồng ghép có chỗ nào chạy vào **no-op** (SEAM_UNWIRED / STUB_UNRESOLVED)?
55
65
  - Độ phủ tổng thể (`code_coverage`) bao nhiêu?
56
66
 
57
67
  ---
58
68
 
59
69
  ## Framework xử lý thế nào (Mechanics)
60
70
 
61
- Phân loại mỗi SC theo **thứ tự ưu tiên** (rule sớm thắng):
71
+ ### Phân loại `status` từng SC (thứ tự ưu tiên, rule sớm thắng)
62
72
 
63
73
  | # | Trạng thái | Điều kiện |
64
74
  |---|-----------|-----------|
65
- | 1 | **UNTRACKED** | `gen_ver == —` — scenario chưa từng sinh code |
75
+ | 0 | **ORPHANED** | SC **không còn trong `.feature`** nhưng `implemented_by != —` — code trỏ vào scenario đã bị xoá |
76
+ | 1 | **UNTRACKED** | `implemented_by == —` — scenario chưa từng sinh code |
66
77
  | 2 | **DRIFT** | có `implemented_by` **và** `spec_ver != gen_ver` — spec đổi sau codegen → **regen trước khi test** |
67
78
  | 3 | **GAP** | có `implemented_by` **và** (`test_count == — / 0`) — có code, chưa test |
68
79
  | 4 | **OK** | `spec_ver == gen_ver`, có `implemented_by`, `test_count > 0` |
69
80
 
81
+ > **Vì sao ORPHANED là Rule 0:** 4 rule kia đều giả định scenario **còn tồn tại** — chúng trả lời *"spec này implement tới đâu"*. `ORPHANED` trả lời câu ngược: *"code này còn spec nào bảo lãnh không"*. Để rule khác thắng thì mỗi giá trị **route người dùng sang một lệnh vô nghĩa**: `GAP` → sinh test cho SC không tồn tại · `DRIFT` → regen từ SC đã xoá · `OK` → cho tạo PR.
82
+ >
70
83
  > **Vì sao DRIFT xét trước GAP:** một SC đã có code, chưa test, **và** spec vừa drift phải hiện `DRIFT` (không phải `GAP`) — vì `/generate-code` xử `GAP` = "skip codegen" còn `DRIFT` = "regenerate". Nếu GAP thắng, code lỗi thời bị bỏ qua và test sinh trên code cũ.
71
84
 
85
+ `code_coverage = (rows where implemented_by != —) / total_scs` — và **`total_scs` loại row `ORPHANED`**: nó không còn là scope, tính vào mẫu số sẽ bóp méo coverage vì một thứ không ai cần implement.
86
+
87
+ ### Hai chiều quét
88
+
89
+ | Chiều | Bước | Bắt gì |
90
+ |---|---|---|
91
+ | **spec → code** | Step 2 | mỗi row `.tsv` — SC đó implement/test tới đâu |
92
+ | **code → spec** | Step 2b | tag `@trace.implements`/`@trace.verifies` trỏ SC **không tồn tại** |
93
+
94
+ Chiều ngược là cần thiết vì gen lại BDD có thể làm một SC biến mất (gộp / đổi số / xoá) trong khi code implement nó vẫn nằm đó, vẫn được caller gọi. Không có Step 2b thì method đó **vô hình**: không status nào, không report nào — và coverage còn *đẹp hơn* thực tế vì mẫu số nhỏ đi.
95
+
96
+ ### Cờ drift — 6 tầng
97
+
98
+ | Cờ | So cái gì | Step |
99
+ |---|---|:---:|
100
+ | `PRD_DRIFT` | Version PRD vs cột `prd_version` vs `@trace.prd_version` trong code — **và** changelog **có** nêu UC này | 4 |
101
+ | `TECHDOC_DRIFT` · `FE_TECHDOC_DRIFT` | `@trace.revision` tech-doc vs cột đã lưu — **và** changelog nêu UC này | 5 |
102
+ | `BDD_DRIFT` | `@trace.bdd_version` trong code vs `.feature` hiện tại | 5c |
103
+ | `TECHDOC_STALE_VS_BDD` | map `@trace.bdd_versions` của tech-doc vs `.feature` hiện tại | 5c |
104
+ | `DESIGNSPEC_DRIFT` | `@trace.design_spec_version` trong code FE vs Version design-spec *(chỉ FE/App)* | 5d |
105
+ | `DESIGNSPEC_STALE_VS_BDD` | cột `design_spec_version` vs Version design-spec — BDD dựng từ bản cũ, **có thể thiếu Screen State / AC-UI vừa thêm** | 5d |
106
+
107
+ **Design-spec vào trace từ v0.4.3.** Trước đó nó là artifact upstream **duy nhất** không có cột TSV, không có tag trong code, không có cờ — dù nó điều khiển **cả** BDD FE/App (Screen States + AC-UI) **lẫn** code FE (màn hình, component inventory, Figma frame). Nó tự bảo vệ **một chiều** (reset `draft` khi PRD đổi); chiều *"designer sửa design-spec **sau khi** BDD/code đã sinh"* thì không gì bắt được.
108
+
109
+ `BDD_DRIFT` **bổ trợ** cho `sc_version`, không thay thế: `sc_version` bắt thay đổi trong **thân scenario**, `bdd_version` bắt thay đổi **cấp file** mà `sc_version` không thấy (Background, `@trace.dataset`, Business Definition, Coverage Matrix).
110
+
111
+ `TECHDOC_STALE_VS_BDD` là ca nguy hiểm nhất trong bảng: `/generate-code` DS3 thấy tech-doc `approved` sẽ lấy shape §4 **nguyên văn** làm contract "đã chốt" — contract dựng từ BDD cũ lan **thẳng** vào code. Cổng chặn nằm ở [`/review-tech-docs` **T3b**](05-tech-docs.md).
112
+
113
+ ### 4 cờ 🔴 — chặn PR
114
+
115
+ | Cờ | Nghĩa |
116
+ |---|---|
117
+ | `ORPHANED` | code còn, scenario đã bị xoá khỏi `.feature` (row `.tsv` được giữ lại **chủ động**) |
118
+ | `TRACE_ORPHAN` | tag trỏ SC không tồn tại **và không có row `.tsv`** — nợ cũ, **không chỗ nào khác bắt được** |
119
+ | `SEAM_UNWIRED` | hàng thật đã có nhưng consumer còn wire vào stub → luồng chạy vào no-op |
120
+ | `STUB_UNRESOLVED` | method còn trắng dù owner UC đã gen / đã đẻ hàm song song |
121
+
122
+ > `SEAM_PENDING` / `STUB_PENDING` (owner chưa gen) là **bình thường** — chỉ nhắc.
123
+ >
124
+
125
+ ### 2 cờ ⓘ — báo động oan đã được lọc ra
126
+
127
+ | Cờ | Nghĩa | Đường ra |
128
+ |---|---|---|
129
+ | `PRD_STALE_REF` | Version PRD lệch **nhưng changelog KHÔNG nêu UC này** → nội dung không đổi, chỉ con trỏ cũ | `--realign-prd-version {UC-ID}` |
130
+ | `TECHDOC_STALE_REF` | Đối xứng, cho tech-doc | `--realign-techdoc-revision {UC-ID}` |
131
+
132
+ **Vì sao cần tách hai cờ này ra.** PRD là tài liệu **cấp feature** phủ nhiều UC, nhưng Version của nó là **một scalar**. Thêm UC7 — không đụng một chữ nào của UC1–UC6 — vẫn làm **cả 6 UC cũ lệch version**. So version thuần thì cả 6 ăn cờ đỏ **oan**.
133
+
134
+ Tệ hơn: **làm theo hướng dẫn cũng không tắt được.** `/generate-bdd` sạch được cột TSV, nhưng tag trong code chỉ `/generate-code` ghi — mà nó thấy row đang `OK` là **skip**. Vòng lặp đóng, và lối ra duy nhất là ép sinh lại code cho hàng loạt UC không hề thay đổi.
135
+
136
+ Bộ lọc đọc **scope của row changelog** (`/refine-prd` Phase 3 và `/extend-prd` bắt buộc ghi UC/AC/BR bị ảnh hưởng — `/generate-bdd` Version Check đã dùng dữ liệu này từ trước). **Row nào mơ hồ → gắn 🟠 cho MỌI UC** — lưới an toàn: mất tính năng *lọc*, không mất tính năng *cảnh báo*.
137
+
138
+ > Đây là bài mà framework **đã giải đúng ở cấp scenario**: `sc_version` chỉ bump khi thân scenario thực sự đổi, vì *"bump vô cớ sẽ tạo DRIFT giả, làm cờ mất giá trị"*. Hai cờ ⓘ là bản tương ứng ở cấp tài liệu.
139
+
140
+ ### Realign — đường ra cho cờ ⓘ
141
+
142
+ ```bash
143
+ /validate-traces --realign-prd-version {UC-ID}
144
+ /validate-traces --realign-techdoc-revision {UC-ID}
145
+ ```
146
+
147
+ Cập nhật cột TSV **và** tag trong code lên version hiện tại. **Ba rào an toàn:**
148
+
149
+ 1. **Từ chối chạy** nếu UC đang `DRIFT` / `ORPHANED` / bị gắn 🟠 — khi đó nội dung **đổi thật**, dán nhãn lại là **che lỗi**
150
+ 2. **Chỉ sửa dòng `@trace.*`** — guard sau-ghi diff lại, lệch là khôi phục file
151
+ 3. **In chính xác** file + dòng đã sửa — realign im lặng là realign không kiểm chứng được
152
+
153
+ > Không đụng `dev_selftest`/`qc_status`: tiền đề của realign là **không có logic nào đổi**, nên luật *"làm mất hiệu lực"* không áp.
154
+
155
+ ### Nhật ký lịch sử — đo *tốc độ*, không chỉ *trạng thái*
156
+
157
+ `trace-report.json` bị **ghi đè** mỗi lần chạy, và cột `last_updated` chỉ là một ngày bị 8 lệnh cùng ghi đè. Nên framework đo **trạng thái** rất tốt nhưng không đo được **tốc độ**.
158
+
159
+ Step 8c append 1 dòng *delta* vào `{trace_dir}/trace-history.jsonl` mỗi lần chạy — vài trăm byte, rotate theo tháng — rồi in:
160
+
161
+ ```
162
+ 📈 So lần chạy trước (12/08): code +2% · test −1% · DRIFT +3 · UNTRACKED −5
163
+ Đèn mới bật: SEAM_UNWIRED × 1 · Đèn đã tắt: STUB_UNRESOLVED × 2
164
+ ```
165
+
166
+ Trả lời được: *lệch từ bao giờ · đang lên hay xuống · case này hỏng đi hỏng lại mấy lần · sprint vừa rồi đóng được bao nhiêu.*
167
+
168
+ | Ràng buộc | Vì sao |
169
+ |---|---|
170
+ | Chỉ ghi vào `{trace_dir}`, **không** mirror | Nhân bản dữ liệu tích luỹ ra chỗ sinh-ra = hai lịch sử lệch nhau |
171
+ | **Phải commit** cùng `.tsv` | Là **dữ liệu**, không regenerate được |
172
+ | Không đụng TSV / `trace-report.json` | TSV là bảng **trạng thái** (giữ phẳng); JSON là contract với panel |
173
+ | **Không lệnh nào gác cổng dựa trên nó** | Để **nhìn**, không phải để chặn. Cổng PR vẫn chỉ là 4 cờ 🔴 |
174
+ > **Build xanh, test từng-UC xanh, coverage đẹp — vẫn có thể còn 🔴.** Đó chính là lớp lỗi mà hai thứ kia không bắt được. `ORPHANED`/`TRACE_ORPHAN` **không tự hết**: phải có người quyết định xoá code+test, hay đưa scenario trở lại `.feature`.
175
+
176
+ ### Tín hiệu FE còn dùng mock
177
+
178
+ `fe_on_mock` = số SC có `fe_phase = ui` — FE đã có UI nhưng **chưa wire API thật**. Các SC này có thể đang hiện `OK` (có code, có test) nhưng **test chạy trên mock** → đừng coi là xong tính năng. Route: `/generate-code {feature-file} --phase=integration`.
179
+
72
180
  ---
73
181
 
74
182
  ## HITL / Gate
@@ -81,11 +189,23 @@ Phân loại mỗi SC theo **thứ tự ưu tiên** (rule sớm thắng):
81
189
 
82
190
  ```
83
191
  /validate-traces auth
84
- UC-01 SC-01.1 OK
85
- UC-01 SC-01.2 GAP (code, chưa test)
86
- UC-02 SC-02.1 DRIFT (spec_ver 1.1 gen_ver 1.0 regen)
87
- UC-02 SC-02.3 UNTRACKED (chưa sinh code)
88
- code_coverage = 7/9 (78%)
192
+
193
+ 🔴 GATE — MỒ CÔI: 1 SEAM_UNWIRED · 0 STUB_UNRESOLVED · 1 ORPHANED · 0 TRACE_ORPHAN
194
+ Build xanh, test từng-UC xanh, coverage đẹp nhưng luồng ghép chạy vào no-op,
195
+ hoặc code đang trỏ vào scenario đã bị xoá. KHÔNG coi là pass tới khi CẢ BỐN = 0.
196
+
197
+ AUTH-UC1 SC1 OK
198
+ AUTH-UC1 SC2 GAP (có code, chưa test)
199
+ AUTH-UC2 SC1 DRIFT (spec_ver 1.1 ≠ gen_ver 1.0 → regen)
200
+ AUTH-UC2 SC3 UNTRACKED (chưa sinh code)
201
+ AUTH-UC2 SC7 ORPHANED ⚠ đã xoá khỏi spec nhưng code còn
202
+ code_coverage = 7/9 (78%) ← mẫu số KHÔNG tính row ORPHANED
203
+
204
+ BDD Version Drift:
205
+ AUTH-UC1 (web) — code sinh từ BDD v1.4, .feature giờ v1.6 [SC đang DRIFT: SC2]
206
+
207
+ FE còn dùng mock (fe_phase = ui):
208
+ AUTH-UC1 (web) — 3 SC — có test nhưng chạy trên mock, chưa nối API thật
89
209
  ```
90
210
 
91
211
  ---
@@ -94,11 +214,16 @@ Phân loại mỗi SC theo **thứ tự ưu tiên** (rule sớm thắng):
94
214
 
95
215
  - ❌ Coi validate-traces là "chạy xong là fix xong" — nó chỉ báo cáo; hành động ở `/generate-code` (regen DRIFT) và QC (bù GAP).
96
216
  - ❌ Bỏ qua DRIFT rồi test trên code cũ.
217
+ - ❌ **Tạo PR khi còn cờ 🔴.** Build xanh không chứng minh luồng ghép chạy đúng.
218
+ - ❌ Coi `fe_phase = ui` là xong vì status đã `OK` — test đang chạy trên mock.
219
+ - ❌ Xoá row `ORPHANED` khỏi `.tsv` cho "sạch bảng" — làm thế là đưa code mồ côi về trạng thái **vô hình**, đúng cái bug mà Rule 0 sinh ra để chống.
97
220
 
98
221
  ---
99
222
 
100
223
  ## Bước tiếp theo (Next step)
101
224
 
225
+ **Thứ tự xử lý:** cờ 🔴 trước (chặn PR) → rồi drift → rồi GAP. Route đầy đủ nằm ở bảng "Gợi ý lệnh tiếp theo" cuối report.
226
+
102
227
  Gap/drift phát hiện → quay lại `/generate-code` (regen) hoặc bù test; lỗi/thiếu từ QC → vòng phản hồi:
103
228
 
104
229
  ➡️ [Bước 10 · Feedback Loop — `/report-bug` · `/propose-scenario` · `/learn` · `/sync`](10-feedback-loop.md)
@@ -32,11 +32,25 @@ Framework là pipeline **một chiều** — nhưng vẫn cần đường **ph
32
32
  | Lệnh | Ai dùng | Kết quả | Đi về đâu |
33
33
  |------|---------|---------|-----------|
34
34
  | `/report-bug` | Tester / QC | Bug **spec-anchored** (gồm product-gap từ `/qc-*`) | `feedback/bug-reports/` |
35
- | `/propose-scenario` | Tester / QC | Đề xuất BDD scenario mới | `feedback/bdd-proposals/` |
35
+ | `/propose-scenario` **Case A** | Tester / QC | Thiếu scenario cho **AC đã có** | `feedback/bdd-proposals/` |
36
+ | `/propose-scenario` **Case B** | Tester / QC | **Requirement MỚI** — không AC nào phủ | `feedback/prd-change-requests/` |
36
37
  | `/learn` | Tất cả | Guardrail lesson | `project-lessons.md` (qua step `capture-lesson`) |
37
38
  | `/fix-bug` | Dev | Sửa lỗi có root-cause + regression test | Code + `@trace.fixes/root_cause/regression` |
39
+ | `/extend-prd` | PO | **Drain** PRD change request → UC/AC/BR mới trong PRD | PRD v+1 · request → `archived/` |
38
40
  | `/sync` | Lead (umbrella) | Pull + submodule + **nổi feedback** + làm mới Living Docs | Chạy hằng ngày |
39
41
 
42
+ ### Ba hàng đợi — mỗi cái phải có người lấy ra
43
+
44
+ | Hàng đợi | Ai bỏ vào | Ai **lấy ra** | Ai **nhắc lại** |
45
+ |---|---|---|---|
46
+ | `bug-reports/` | `/report-bug` | `/fix-bug` (quét thư mục mỗi lần chạy) | cột `qc_blocked_by` của TSV |
47
+ | `bdd-proposals/` | `/propose-scenario` A | `/generate-bdd` (quét mỗi lần chạy, 9 bước: chèn → normalize → append row TSV → archive → commit) | — |
48
+ | `prd-change-requests/` | `/propose-scenario` B | **`/extend-prd`** | `/validate-traces` Step 7b — đếm `Status: Open` kèm **số ngày chờ** |
49
+
50
+ > **Vì sao cột "ai nhắc lại" quan trọng.** `/sync` chỉ hiện những gì về **trong đúng lần pull đó** (`git diff old..new`) — nó là **chuông cửa, không phải tồn kho**. Bỏ lỡ một lần là mất khỏi màn hình vĩnh viễn. Hai hàng đợi đầu không sao vì có lệnh **quét lại thư mục mỗi lần chạy**; riêng `prd-change-requests/` thì không — nên `/validate-traces` phải nhắc thay.
51
+ >
52
+ > Trước v0.4.3, hàng đợi thứ ba **không có người lấy ra**: có producer, có storage, có commit, có mặt trong `/sync` — nhưng 0 consumer, và **không gì báo**. Yêu cầu nghiệp vụ thật do tester phát hiện từ sản phẩm chạy thật rơi vào im lặng hoàn toàn. Từ v0.4.3, cả ba hàng đợi được khai vào `bin/trace-schema.json` §`queues` nên **self-check chặn build** nếu một hàng đợi mất consumer.
53
+
40
54
  ---
41
55
 
42
56
  ## Ai làm gì (Roles & responsibilities)
@@ -64,10 +78,47 @@ Framework là pipeline **một chiều** — nhưng vẫn cần đường **ph
64
78
 
65
79
  1. **`/report-bug` / `/propose-scenario`** — ghi feedback kèm tham chiếu spec vào `feedback/` (spec repo nếu umbrella).
66
80
  2. **`/learn`** — qua step `capture-lesson`, ghi guardrail vào `project-lessons.md`; các workflow sau **nạp lại** vào context → hệ thống *nhớ*.
67
- 3. **`/generate-bdd`** — có thể incorporate scenario proposal đã `accepted`.
68
- 4. **`/fix-bug`** — đọc bug spec-anchoredtạo branch `fix/{TICKET}-<slug>`root causesửa (tag `@trace.fixes/root_cause/regression`)regression test + build verifycommit sau khi user duyệt.
81
+ 3. **`/generate-bdd`** — incorporate scenario proposal đã `accepted`, kèm **normalize** (xem dưới).
82
+ 3b. **`/extend-prd`** — nhặt PRD change request `accepted` làm **nguyên liệu** (không chèn thẳng: yêu cầu nghiệp vụ phải qua PO chốt AC/BR đúng tầng) discovery delta + **kiểm va chạm** với UC/BR đã có đánh số **nối tiếp** ghi **add-only** + guard sau-ghi bump version + changelog nêu rõ scope đóng dấu `incorporated` + `archived/` + commit.
83
+ 4. **`/fix-bug`** — đọc bug spec-anchored → branch `fix/{TICKET}-<slug>` → root cause → sửa (tag `@trace.fixes/root_cause/regression`) → regression test + build verify → **cập nhật sổ trace** → commit sau khi user duyệt.
69
84
  5. **`/sync`** — pull, init submodule, **nổi feedback** lên PO/Dev, bootstrap config service, làm mới Living Docs. An toàn chạy lặp lại.
70
85
 
86
+ ### Vòng đời bug — mỗi bước có đúng một chủ
87
+
88
+ | State | Ai đặt | Khi nào |
89
+ |---|---|---|
90
+ | `🟢 Open` | `/report-bug` | tester/QC file bug |
91
+ | `🟡 Fixed` | `/fix-bug` Phase 5.5 | fix đã commit + push |
92
+ | `🟢 Closed` | **`/qc-run-test`** | QC chạy lại và `qc_status` của SC liên kết flip `pass` |
93
+
94
+ > **Dev không tự đóng bug của mình** — QC sở hữu verification. `/qc-run-test` đọc `qc_blocked_by` **trước** khi clear nó (cột đó chính là con trỏ tới bug; clear xong là mất đường về).
95
+ >
96
+ > Ngoại lệ có chủ đích: SC pass mà bug còn `🟢 Open` (chưa ai fix) → **không đóng**, giữ `Open` + cảnh báo kiểm tra lại test. Test pass trên bug chưa fix là dấu hiệu **test sai**, không phải bug hết — tự đóng ở đây sẽ chôn một defect thật.
97
+
98
+ ### `/fix-bug` ghi gì vào sổ trace
99
+
100
+ Regression test không phải test "ngoài luồng" — nó phải hiện lên coverage:
101
+
102
+ | Cột | Ghi gì |
103
+ |---|---|
104
+ | `test_count` | **+=** số test regression (cộng dồn, không ghi đè) |
105
+ | `test_classes` | **append** tên class mới |
106
+ | `dev_selftest` → `not_run` · `dev_selftest_at` → `—` | code vừa đổi nên tín hiệu self-test cũ hết hiệu lực |
107
+
108
+ **Không** đụng `qc_*` (QC sở hữu) và **không** đụng `spec_ver`/`gen_ver` — fix bug không đổi spec, đụng vào là tạo `DRIFT` giả. Next của `/fix-bug` là `/dev-run-test` để lấy lại tín hiệu xanh, rồi mới tạo PR.
109
+
110
+ ### Proposal của tester — normalize khi chèn
111
+
112
+ `/propose-scenario` viết scenario theo **đúng** bộ tag canonical (`@trace.scenario` với placeholder `SC?` · `@trace.sc_version: 1.0` · `@trace.business_rules`; AC ghi thành comment `# Covers:` chứ **không** phải trace key). Khi `/generate-bdd` chèn proposal `accepted`, nó phải:
113
+
114
+ 1. gán `sc_id` = số SC **kế tiếp** trong file (thay `SC?`)
115
+ 2. bổ sung `@trace.business_rules` nếu proposal để `—`
116
+ 3. **strip** `@proposed` / `@from-test` — nhãn vòng đời proposal, không thuộc BDD canonical
117
+ 4. đặt scenario vào **đúng NHÓM** theo business theme
118
+ 5. **append row `.tsv`** (`spec_ver = 1.0`, `status = UNTRACKED`)
119
+
120
+ > Thiếu bước 1/5 thì scenario vào file mà **không có row trace** → vô hình với toàn bộ coverage và drift.
121
+
71
122
  ---
72
123
 
73
124
  ## HITL / Gate
@@ -86,6 +137,11 @@ QC phát hiện: link reset vẫn dùng được sau khi đổi mật khẩu
86
137
  /fix-bug BUG-217 → branch fix/BUG-217-invalidate-link
87
138
  → root cause: thiếu invalidate token
88
139
  → fix + regression test + build ✅
140
+ → trace: test_count +2, dev_selftest → not_run
141
+ → BUG-217 State: 🟡 Fixed
142
+ /dev-run-test AUTH-UC2 → dev_selftest → pass
143
+ /qc-run-test AUTH-UC2 → qc_status SC1 → pass
144
+ → BUG-217 State: 🟢 Closed (verified)
89
145
  /learn "luôn invalidate one-time token sau khi dùng"
90
146
  → project-lessons.md (nạp lại lần sau)
91
147
  ```
@@ -70,4 +70,4 @@ QC █████ 🟠 cổng review test & script
70
70
 
71
71
  ## Đọc theo vai trò của bạn (Role Guides)
72
72
 
73
- → [Product Owner](../../03-guides/product-owner.md) · [Developer](../../03-guides/developer.md) · [Architect](../../03-guides/architect.md) · [Tester/QA](../../03-guides/tester-qa.md)
73
+ → [Product Owner](../03-guides/product-owner.md) · [Developer](../03-guides/developer.md) · [Architect](../03-guides/architect.md) · [Tester/QA](../03-guides/tester-qa.md)