@educa-corp/sdd-framework 0.6.0 → 0.7.1

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 (223) hide show
  1. package/bin/gate-trace.js +25 -2
  2. package/bin/index.js +32 -5
  3. package/bin/lint-trace.js +41 -0
  4. package/bin/self-check.js +430 -3
  5. package/bin/trace-schema.json +418 -31
  6. package/core/FRAMEWORK_VERSION +1 -1
  7. package/{commands/extend-prd.md → core/commands/amend-prd.md} +206 -173
  8. package/core/commands/dev-run-test.md +48 -10
  9. package/core/commands/extend-prd.md +39 -12
  10. package/core/commands/generate-bdd.md +52 -10
  11. package/core/commands/generate-code.md +35 -2
  12. package/core/commands/generate-tech-docs.md +36 -4
  13. package/core/commands/map-testids.md +1 -1
  14. package/core/commands/qc-run-test.md +29 -3
  15. package/core/commands/refine-prd.md +13 -2
  16. package/core/commands/review-context.md +43 -8
  17. package/core/commands/sync.md +105 -1
  18. package/core/commands/validate-traces.md +289 -16
  19. package/core/rules/workflow.md +34 -0
  20. package/core/steps/context-loader.md +27 -6
  21. package/core/templates/feature.template +1 -1
  22. package/core/templates/project-context.yaml +3 -3
  23. package/core/templates/tech-design.template.md +2 -2
  24. package/docs/02-concepts/architecture.md +37 -1
  25. package/docs/02-concepts/overview.md +1 -1
  26. package/docs/02-concepts/pipeline-steps/02-specification.md +13 -7
  27. package/docs/02-concepts/pipeline-steps/07-dev-selftest.md +2 -0
  28. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +1 -0
  29. package/docs/02-concepts/pipeline-steps/09-validate-traces.md +34 -3
  30. package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +10 -1
  31. package/docs/02-concepts/traceability.md +187 -183
  32. package/docs/03-guides/architect.md +13 -4
  33. package/docs/03-guides/developer.md +1 -0
  34. package/docs/03-guides/product-owner.md +89 -72
  35. package/docs/03-guides/tester-qa.md +81 -81
  36. package/docs/04-reference/commands.md +148 -134
  37. package/docs/04-reference/trace-schema.md +45 -1
  38. package/docs/explain/02b-extend-prd.md +1 -1
  39. package/docs/explain/02c-amend-prd.md +152 -0
  40. package/docs/explain/06-generate-bdd.md +1 -1
  41. package/docs/explain/13-dev-run-test.md +15 -1
  42. package/docs/explain/19-qc-run-test.md +91 -87
  43. package/docs/explain/21-validate-traces.md +79 -75
  44. package/docs/explain/28-sync.md +25 -0
  45. package/docs/explain/README.md +136 -135
  46. package/package.json +1 -8
  47. package/commands/debug.md +0 -529
  48. package/commands/debug.tmpl +0 -260
  49. package/commands/define-product.md +0 -438
  50. package/commands/define-product.tmpl +0 -225
  51. package/commands/dev-gen-test.md +0 -700
  52. package/commands/dev-gen-test.tmpl +0 -490
  53. package/commands/dev-run-test.md +0 -435
  54. package/commands/dev-run-test.tmpl +0 -225
  55. package/commands/dev-smoke-test.md +0 -374
  56. package/commands/dev-smoke-test.tmpl +0 -217
  57. package/commands/extend-prd.tmpl +0 -273
  58. package/commands/fix-bug.md +0 -519
  59. package/commands/fix-bug.tmpl +0 -197
  60. package/commands/generate-architecture.md +0 -354
  61. package/commands/generate-architecture.tmpl +0 -197
  62. package/commands/generate-bdd.md +0 -923
  63. package/commands/generate-bdd.tmpl +0 -590
  64. package/commands/generate-code.md +0 -859
  65. package/commands/generate-code.tmpl +0 -649
  66. package/commands/generate-design-spec.md +0 -737
  67. package/commands/generate-design-spec.tmpl +0 -524
  68. package/commands/generate-prd.md +0 -722
  69. package/commands/generate-prd.tmpl +0 -226
  70. package/commands/generate-spec-manifest.md +0 -321
  71. package/commands/generate-spec-manifest.tmpl +0 -164
  72. package/commands/generate-tech-docs.md +0 -920
  73. package/commands/generate-tech-docs.tmpl +0 -273
  74. package/commands/learn.md +0 -399
  75. package/commands/learn.tmpl +0 -130
  76. package/commands/map-testids.md +0 -238
  77. package/commands/map-testids.tmpl +0 -81
  78. package/commands/propose-scenario.md +0 -359
  79. package/commands/propose-scenario.tmpl +0 -202
  80. package/commands/qc-analyze.md +0 -269
  81. package/commands/qc-analyze.tmpl +0 -112
  82. package/commands/qc-design-test.md +0 -226
  83. package/commands/qc-design-test.tmpl +0 -69
  84. package/commands/qc-plan.md +0 -206
  85. package/commands/qc-plan.tmpl +0 -49
  86. package/commands/qc-report.md +0 -217
  87. package/commands/qc-report.tmpl +0 -60
  88. package/commands/qc-review.md +0 -210
  89. package/commands/qc-review.tmpl +0 -53
  90. package/commands/qc-run-test.md +0 -326
  91. package/commands/qc-run-test.tmpl +0 -116
  92. package/commands/refine-prd.md +0 -653
  93. package/commands/refine-prd.tmpl +0 -281
  94. package/commands/report-bug.md +0 -305
  95. package/commands/report-bug.tmpl +0 -148
  96. package/commands/review-code.md +0 -415
  97. package/commands/review-code.tmpl +0 -146
  98. package/commands/review-context.md +0 -902
  99. package/commands/review-context.tmpl +0 -530
  100. package/commands/review-tech-docs.md +0 -561
  101. package/commands/review-tech-docs.tmpl +0 -404
  102. package/commands/setup-ai-first.md +0 -602
  103. package/commands/setup-ai-first.tmpl +0 -450
  104. package/commands/sync.md +0 -430
  105. package/commands/sync.tmpl +0 -429
  106. package/commands/update-framework.md +0 -203
  107. package/commands/update-framework.tmpl +0 -202
  108. package/commands/validate-traces.md +0 -1077
  109. package/commands/validate-traces.tmpl +0 -920
  110. package/hooks/data-guard.js +0 -232
  111. package/hooks/settings.json +0 -19
  112. package/modules/android-compose/module.yaml +0 -13
  113. package/modules/android-compose/stack-profile.yaml +0 -57
  114. package/modules/angular/architecture-snippets/component-patterns.md +0 -187
  115. package/modules/angular/module.yaml +0 -6
  116. package/modules/angular/stack-profile.yaml +0 -38
  117. package/modules/context-engineering/architecture-snippets/context-design.md +0 -119
  118. package/modules/context-engineering/module.yaml +0 -9
  119. package/modules/context-engineering/stack-profile.yaml +0 -61
  120. package/modules/dotnet/architecture-snippets/clean-arch.md +0 -160
  121. package/modules/dotnet/module.yaml +0 -6
  122. package/modules/dotnet/stack-profile.yaml +0 -50
  123. package/modules/flutter/module.yaml +0 -14
  124. package/modules/flutter/stack-profile.yaml +0 -59
  125. package/modules/golang/architecture-snippets/domain-layout.md +0 -283
  126. package/modules/golang/module.yaml +0 -6
  127. package/modules/golang/stack-profile.yaml +0 -40
  128. package/modules/ios-swiftui/module.yaml +0 -13
  129. package/modules/ios-swiftui/stack-profile.yaml +0 -55
  130. package/modules/java-spring/architecture-snippets/layered-arch.md +0 -201
  131. package/modules/java-spring/module.yaml +0 -15
  132. package/modules/java-spring/stack-profile.yaml +0 -28
  133. package/modules/nextjs/architecture-snippets/app-router-patterns.md +0 -269
  134. package/modules/nextjs/module.yaml +0 -14
  135. package/modules/nextjs/stack-profile.yaml +0 -74
  136. package/modules/nuxt/module.yaml +0 -14
  137. package/modules/nuxt/stack-profile.yaml +0 -58
  138. package/modules/phaser-game/architecture-snippets/phaser-scene-patterns.md +0 -646
  139. package/modules/phaser-game/module.yaml +0 -15
  140. package/modules/phaser-game/stack-profile.yaml +0 -90
  141. package/modules/php-laravel/architecture-snippets/service-repository.md +0 -302
  142. package/modules/php-laravel/module.yaml +0 -15
  143. package/modules/php-laravel/stack-profile.yaml +0 -56
  144. package/modules/qc-playwright/stack-profile.yaml +0 -66
  145. package/modules/react/architecture-snippets/hooks-query-patterns.md +0 -254
  146. package/modules/react/module.yaml +0 -14
  147. package/modules/react/stack-profile.yaml +0 -63
  148. package/modules/react-native/module.yaml +0 -14
  149. package/modules/react-native/stack-profile.yaml +0 -56
  150. package/modules/vue/module.yaml +0 -14
  151. package/modules/vue/stack-profile.yaml +0 -65
  152. package/rules/data-protection.md +0 -80
  153. package/rules/workflow.md +0 -99
  154. package/skills/code/SKILL.md +0 -19
  155. package/skills/code/SKILL.tmpl +0 -19
  156. package/skills/debug/SKILL.md +0 -19
  157. package/skills/debug/SKILL.tmpl +0 -19
  158. package/skills/design-spec/SKILL.md +0 -11
  159. package/skills/design-spec/SKILL.tmpl +0 -11
  160. package/skills/discovery/SKILL.md +0 -14
  161. package/skills/discovery/SKILL.tmpl +0 -14
  162. package/skills/prd/SKILL.md +0 -19
  163. package/skills/prd/SKILL.tmpl +0 -19
  164. package/skills/qc/qa-analyst/DOC_GAPS.template.md +0 -63
  165. package/skills/qc/qa-analyst/acceptance-criteria.md +0 -60
  166. package/skills/qc/qa-analyst/business-rules.md +0 -59
  167. package/skills/qc/qa-analyst/data-flow.md +0 -64
  168. package/skills/qc/qa-analyst/spec-breakdown.md +0 -61
  169. package/skills/qc/qa-designer/e2e/journey.md +0 -41
  170. package/skills/qc/qa-designer/exploratory/charter.md +0 -68
  171. package/skills/qc/qa-designer/exploratory/explore-to-functional.md +0 -43
  172. package/skills/qc/qa-designer/functional/api.md +0 -45
  173. package/skills/qc/qa-designer/functional/gui-feature.md +0 -46
  174. package/skills/qc/qa-designer/functional/gui-screen.md +0 -52
  175. package/skills/qc/qa-designer/integration/api.md +0 -42
  176. package/skills/qc/qa-designer/integration/db.md +0 -39
  177. package/skills/qc/qa-designer/integration/gui.md +0 -40
  178. package/skills/qc/qa-designer/integration/kafka.md +0 -40
  179. package/skills/qc/qa-designer/non-functional.md +0 -40
  180. package/skills/qc/qa-planner/test-plan.md +0 -120
  181. package/skills/qc/qa-reviewer/script/e2e.md +0 -87
  182. package/skills/qc/qa-reviewer/script/exploratory.md +0 -45
  183. package/skills/qc/qa-reviewer/script/functional.md +0 -101
  184. package/skills/qc/qa-reviewer/script/integration.md +0 -91
  185. package/skills/qc/qa-reviewer/script/non-functional.md +0 -126
  186. package/skills/qc/qa-reviewer/test-case/e2e.md +0 -73
  187. package/skills/qc/qa-reviewer/test-case/exploratory.md +0 -43
  188. package/skills/qc/qa-reviewer/test-case/functional.md +0 -76
  189. package/skills/qc/qa-reviewer/test-case/integration.md +0 -69
  190. package/skills/qc/qa-reviewer/test-case/non-functional.md +0 -73
  191. package/skills/qc/qa-runner/e2e.md +0 -49
  192. package/skills/qc/qa-runner/exploratory/session.md +0 -36
  193. package/skills/qc/qa-runner/functional/api.md +0 -35
  194. package/skills/qc/qa-runner/functional/gui-feature.md +0 -51
  195. package/skills/qc/qa-runner/functional/gui-screen.md +0 -55
  196. package/skills/qc/qa-runner/integration.md +0 -47
  197. package/skills/qc/qa-runner/non-functional.md +0 -49
  198. package/skills/qc/qa-runner/report/report.md +0 -37
  199. package/skills/setup-ai-first/SKILL.md +0 -19
  200. package/skills/setup-ai-first/SKILL.tmpl +0 -19
  201. package/skills/spec/SKILL.md +0 -19
  202. package/skills/spec/SKILL.tmpl +0 -19
  203. package/skills/test/SKILL.md +0 -18
  204. package/skills/test/SKILL.tmpl +0 -18
  205. package/steps/business-language.md +0 -56
  206. package/steps/capture-lesson.md +0 -112
  207. package/steps/context-loader.md +0 -406
  208. package/steps/gate.md +0 -151
  209. package/steps/report-footer.md +0 -125
  210. package/steps/review-fanout.md +0 -159
  211. package/steps/spawn-agent.md +0 -129
  212. package/steps/trace-mirror.md +0 -53
  213. package/templates/README.md +0 -70
  214. package/templates/architecture.template.md +0 -394
  215. package/templates/ci/trace-gate.yml +0 -146
  216. package/templates/design-spec.template.md +0 -217
  217. package/templates/feature.template +0 -123
  218. package/templates/hooks/pre-push +0 -61
  219. package/templates/platform-guide.template.md +0 -145
  220. package/templates/prd.template.md +0 -283
  221. package/templates/product-definition.template.md +0 -188
  222. package/templates/project-context.yaml +0 -212
  223. package/templates/tech-design.template.md +0 -490
@@ -1,183 +1,187 @@
1
- [← Roles & HITL](roles-and-hitl.md) · [Concepts](./) · [Architecture →](architecture.md)
2
-
3
- # Traceability — Truy vết đầu-cuối (End-to-end Trace)
4
-
5
- > Từ scenario nhìn xuống biết code nào hiện thực; từ code nhìn lên biết scenario nào yêu cầu. Đây là một trong ba "trái tim" của framework.
6
-
7
- ---
8
-
9
- ## Trace tags theo artifact
10
-
11
- | Artifact | Trace tag |
12
- |----------|-----------|
13
- | **BDD file** (header) | `@trace.id` · **`@trace.platform`** · **`@trace.service`** · `@trace.module` · `@trace.domain` · `@trace.prd` · `@trace.prd_version` · `@trace.bdd_version` · `@trace.status` · `@trace.dataset` |
14
- | **BDD scenario** (mỗi SC) | `@trace.scenario` · **`@trace.sc_version`** · `@trace.business_rules` |
15
- | **Code** (boundary only) | `@trace.implements` · `@trace.source` · **`@trace.prd_version` · `@trace.bdd_version` · `@trace.tech_doc_revision`** · **`@trace.design_spec_version`** *(chỉ FE/App)* — lặp cả block theo **từng UC** trong file đa-UC |
16
- | **Code** (chỗ chưa implement) | `@trace.stub` · `@trace.stub_owner` · `@trace.stub_for` · `@trace.seam_pending` · `@trace.seam_port` |
17
- | **Test** | `@trace.verifies` |
18
- | **Bug fix** | `@trace.fixes` · `@trace.root_cause` · `@trace.regression` |
19
-
20
- → Đầy đủ field & format: [Reference › Trace Schema](../04-reference/trace-schema.md).
21
-
22
- ---
23
-
24
- ## Boundary-only tagging
25
-
26
- Chỉ tag `@trace` ở **boundary**, không tag mọi file → tránh **tag explosion**:
27
-
28
- | ✅ Tag | ❌ Không tag |
29
- |--------|-------------|
30
- | Controller / Handler / Middleware / Steps file | Entity / Repository / DTO / Interface / Base class |
31
-
32
- > Shared code (entity, repo) được dò qua **import chain** từ boundary — không cần tag riêng.
33
-
34
- ---
35
-
36
- ## Trace state — file `.tsv`
37
-
38
- `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` — mỗi UC × platform một sổ. Trong umbrella, nằm ở **spec repo dùng chung** (một nơi authoritative để PM/PO quản lý).
39
-
40
- | Cột | Chủ sở hữu | Ý nghĩa |
41
- |-----|-----------|---------|
42
- | `status` | `/generate-code`, `/validate-traces` | OK / GAP / DRIFT / UNTRACKED |
43
- | `implemented_by` | `/generate-code` | File code hiện thực SC |
44
- | `dev_selftest` | `/dev-run-test` | Smoke của **dev** |
45
- | `qc_status` | `/qc-run-test`, `/report-bug` | Trạng thái QC **chính thức** (Playwright) |
46
- | `bdd_version` / `spec_ver` | spec | Version để phát hiện drift |
47
- | `service` *(cột 23)* | `/generate-bdd` | Đội/submodule sở hữu SC — nguồn của `by_service` trên dashboard |
48
- | `design_spec_version` *(cột 24)* | `/generate-bdd` | Version design-spec lúc sinh BDD *(FE/App; `—` cho backend)* |
49
-
50
- **24 cột.** TSV cũ thiếu cột mới → đọc thành giá trị rỗng, **không báo lỗi**; header tự nâng ở lần `/generate-bdd` gen lại kế tiếp. Đọc theo **tên cột ở header row**, không theo vị trí.
51
-
52
- > **Làm mất hiệu lực ≠ ghi đè.** Chủ sở hữu là người **duy nhất** ghi giá trị **khẳng định** (`pass`/`fail`/số lượng). Nhưng lệnh nào làm giá trị đó **hết đúng** (spec đổi, code đổi) **bắt buộc** hạ nó về `not_run`/`—`. Giữ một `pass` sinh ra từ spec đã bị sửa là **báo cáo sai**, không phải tôn trọng quyền sở hữu cột. Ngoại lệ có chủ ý: `qc_owner`/`qc_blocked_by` (con trỏ bug vẫn còn giá trị) và `test_count`/`test_classes` (test vẫn trên đĩa — **cảnh báo**, không hạ số, để tỷ lệ coverage không nhảy loạn).
53
- | `gen_ver` | `/generate-code` | Version lúc sinh code (so với `spec_ver`) |
54
- | `test_count` | test | Số test phủ SC |
55
- | `last_updated` | nhiều | Mốc cập nhật |
56
-
57
- > **`dev_selftest` ≠ `qc_status`.** Dev smoke (nhanh, tự kiểm) và QC chính thức (Playwright, evidence) là **hai trục độc lập** — không lấn quyền nhau.
58
-
59
- ---
60
-
61
- ## Phân loại coverage (Coverage Status)
62
-
63
- `/validate-traces` phân loại mỗi SC theo **thứ tự ưu tiên** (rule sớm thắng):
64
-
65
- | # | Trạng thái | Điều kiện | Hành động |
66
- |---|-----------|-----------|-----------|
67
- | 1 | **UNTRACKED** | `gen_ver == —` | Chưa sinh code → `/generate-code` |
68
- | 2 | **DRIFT** | có code **và** `spec_ver != gen_ver` | Spec đổi → **regen trước khi test** |
69
- | 3 | **GAP** | có code **và** `test_count == — / 0` | Có code, chưa test → bù test |
70
- | 4 | **OK** | version khớp, có code, có test | Đủ phủ |
71
-
72
- > **DRIFT xét trước GAP:** SC có code + chưa test + 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.
73
-
74
- ---
75
-
76
- ## Version sống ở đâu — và vì sao code CŨNG mang version
77
-
78
- **Spec là SSOT của "version hiện tại". Code mang version của "lúc tôi được sinh ra".** Hai thứ khác nhau, nên không phải dual SSOT.
79
-
80
- | Nơi | Ghi cái gì | Ai ghi |
81
- |---|---|---|
82
- | `.feature` / PRD / tech-doc | version **hiện tại** của spec — SSOT | tác giả spec |
83
- | `.tsv` `spec_ver` | gương của `@trace.sc_version` hiện tại | `/generate-bdd`, `/validate-traces` |
84
- | `.tsv` `gen_ver` | version scenario **tại thời điểm codegen**, theo từng SC | `/generate-code` |
85
- | **Code** `@trace.prd_version` · `@trace.bdd_version` · `@trace.tech_doc_revision` · `@trace.design_spec_version` | version của **từng artifact upstream** tại thời điểm codegen, theo từng **method** | `/generate-code` |
86
-
87
- Drift = **so các mốc này với nhau**; sự lệch nhau chính là tín hiệu, không phải lỗi dữ liệu:
88
-
89
- - `spec_ver != gen_ver` → `DRIFT` (scenario đổi sau khi sinh code)
90
- - `@trace.prd_version` trong code < Version PRD hiện tại → `PRD_DRIFT`
91
- - `@trace.bdd_version` trong code < `.feature` hiện tại → `BDD_DRIFT`
92
- - `@trace.tech_doc_revision` trong code < `@trace.revision` của tech-doc → `TECHDOC_DRIFT`
93
- - `@trace.design_spec_version` trong code FE < Version design-spec → `DESIGNSPEC_DRIFT`
94
-
95
- > **Lệch version KHÔNG luôn là drift.** PRD và tech-doc là tài liệu **gộp** phủ nhiều UC nhưng chỉ có **một** số version. Thêm UC7 làm mọi UC cũ lệch số dù không đổi một chữ. Nên `/validate-traces` **lọc theo scope của row changelog**: UC có trong danh sách bị ảnh hưởng → `PRD_DRIFT` 🟠; không có → `PRD_STALE_REF` ⓘ (chỉ con trỏ cũ, sạch bằng `--realign-prd-version`); row changelog **mơ hồ** → 🟠 cho mọi UC (lưới an toàn).
96
-
97
- ** sao không thể bỏ tag version trong codechỉ dựa vào `.tsv`:**
98
-
99
- 1. **Độ phân giải khác nhau.** `.tsv` một sổ cho mỗi UC × platform. Một **file code** có thể phục vụ nhiều UC, mỗi UC một version khác nhau chỉ tag đặt cạnh từng method mới diễn đạt được "UC1 bdd v1.4, UC3 v2.1".
100
- 2. **Vòng đời khác nhau.** `.tsv` là artifact **sinh ra**, có thể regen/xoá/mirror; ở chế độ umbrella nó còn nằm ở **repo khác** (spec submodule) với code. Tag trong code là bản ghi duy nhất **đi cùng** code qua mọi lần copy/move/merge.
101
- 3. **Sự lệch nhau là thứ ta muốn đo.** Nếu chỉ có một bản ghi thì không để so đó mới lúc drift trở nên không phát hiện được.
102
-
103
- > ⚠️ **Đừng "tối ưu" bằng cách gỡ tag version khỏi code.** `/validate-traces` Step 4/5/5c **đọc chính các tag đó**; gỡ đi làm drift detection **im lặng** build vẫn xanh, dashboard vẫn đẹp. `/review-code` lăng kính 1 gắn cờ **major** cho mỗi block `@trace.implements` thiếu tag version đi kèm.
104
-
105
- ---
106
-
107
- ## Luồng truy vết (Trace Flow)
108
-
109
- ```mermaid
110
- flowchart LR
111
- PRD["PRD<br/>prd_version"] --> BDD["Scenario<br/>@trace.id + bdd_version"]
112
- BDD --> CODE["Code boundary<br/>@trace.implements/source"]
113
- CODE --> TEST["Test<br/>@trace.verifies"]
114
- BDD -.-> TSV[".tsv state<br/>status/gen_ver/qc_status"]
115
- CODE -.-> TSV
116
- TEST -.-> TSV
117
- TSV --> VM["/validate-traces<br/>Coverage Matrix"]
118
- ```
119
-
120
- ---
121
-
122
- ## Sổ trace trong git — và khi nó conflict
123
-
124
- Sổ trace là **dữ liệu không dựng lại được**, nằm trong git, và **được nhiều người ghi trên
125
- nhiều nhánh song song**. Ba thứ đó cộng lại nghĩa là git phải được dạy cách merge nó.
126
-
127
- ### Luật đã cài sẵn
128
-
129
- `/setup-ai-first` tạo `{trace_dir}/.gitattributes`; `/sync` Step 4c kiểm tạo hộ nếu thiếu:
130
-
131
- ```gitattributes
132
- *.tsv text eol=lf merge=union
133
- *.jsonl text eol=lf merge=union
134
- ```
135
-
136
- | Luật | Không có nó thì sao |
137
- |---|---|
138
- | `merge=union` | Hai nhánh cùng ghi một sổ → **conflict**. Giải bằng "take mine" = **mất row của người kia, im lặng**. Với `trace-history.jsonl` (append cuối file) thì **mọi** cặp nhánh song song đều conflict. |
139
- | `text eol=lf` | Một máy ghi CRLF → git thấy **mọi dòng** đã đổi → union giữ cả hai bản → **nhân đôi cả file**, gồm cả dòng header. Team mixed Windows/macOS gặp ca này mà không ai làm gì sai. |
140
-
141
- `union` là driver **built-in** của git — không ai cần chạy `git config` gì thêm.
142
-
143
- > **`*.json` cố ý KHÔNG trong danh sách.** `trace-report.json` nằm cùng thư mục union
144
- > trên JSON tạo ra **JSON không hợp lệ** → panel VS Code parse lỗi. Nó **sinh lại được**:
145
- > conflict đó thì chạy lại `/validate-traces`, đừng merge tay.
146
-
147
- ### Đánh đổichủ ý: trùng row thay mất row
148
-
149
- `merge=union` **có thể** tạo hai row cùng `sc_id`. Đó **thiết kế**, không phải lỗi:
150
-
151
- ```
152
- trùng row → --lint-trace T4 bắt được → /validate-traces reconcile → sạch
153
- mất row → KHÔNG bắt được → phát hiện sau 3 tuần → khôi phục bằng tay
154
- ```
155
-
156
- Đây là lý do luật merge và `--lint-trace` **một cặp**: union chuyển lỗi từ dạng *im lặng*
157
- sang dạng *bắt được*, cái bắt phải tồn tại. Có union mà không có lint thì chỉ là đổi chỗ lỗi.
158
-
159
- ### Playbook — 4 bước
160
-
161
- Vẫn thấy conflict trong `{trace_dir}/` (nhánh phân kỳ quá xa, hoặc luật vừa mới được thêm):
162
-
163
- 1. **GIỮ CẢ HAI BÊN.** Xoá ba dòng marker (`<<<<<<<`, `=======`, `>>>>>>>`), giữ toàn bộ row
164
- của cả hai phía. **Đừng chọn một bên.**
165
- 2. `npx @educa-corp/sdd-framework --lint-trace` T7 xác nhận không còn marker, T4 chỉ ra row nào trùng.
166
- 3. `/validate-traces` — reconcile row trùng về một row đúng, tính lại `status`.
167
- 4. Commit.
168
-
169
- **Ba điều không bao giờ làm:**
170
-
171
- | ❌ | Vì sao |
172
- |---|---|
173
- | `git checkout --ours/--theirs` trên file trace | Xoá sạch row của một phía. Không có gì báo. |
174
- | Xoá file trace để "cho sạch" rồi chạy lại pipeline | Sổ **không regenerate được** — `trace-history.jsonl` mất là mất vĩnh viễn. |
175
- | Commit khi còn marker | Marker thành một "row" TSV. `--lint-trace` T7 bắt, nhưng nếu chưa cắm vào CI thì nó vào nhánh chung. |
176
-
177
- ---
178
-
179
- ## Đọc tiếp (Next)
180
-
181
- - [Architecture](architecture.md) — 3 lớp & context-loader
182
- - [Pipeline › Validate Traces](pipeline-steps/09-validate-traces.md) — dùng ma trận coverage
183
- - [Reference Trace Schema](../04-reference/trace-schema.md) — field đầy đủ
1
+ [← Roles & HITL](roles-and-hitl.md) · [Concepts](./) · [Architecture →](architecture.md)
2
+
3
+ # Traceability — Truy vết đầu-cuối (End-to-end Trace)
4
+
5
+ > Từ scenario nhìn xuống biết code nào hiện thực; từ code nhìn lên biết scenario nào yêu cầu. Đây là một trong ba "trái tim" của framework.
6
+
7
+ ---
8
+
9
+ ## Trace tags theo artifact
10
+
11
+ | Artifact | Trace tag |
12
+ |----------|-----------|
13
+ | **BDD file** (header) | `@trace.id` · **`@trace.platform`** · **`@trace.service`** · `@trace.module` · `@trace.domain` · `@trace.prd` · `@trace.prd_version` · `@trace.bdd_version` · `@trace.status` · `@trace.dataset` |
14
+ | **BDD scenario** (mỗi SC) | `@trace.scenario` · **`@trace.sc_version`** · `@trace.business_rules` |
15
+ | **Code** (boundary only) | `@trace.implements` · `@trace.source` · **`@trace.prd_version` · `@trace.bdd_version` · `@trace.tech_doc_revision`** · **`@trace.design_spec_version`** *(chỉ FE/App)* — lặp cả block theo **từng UC** trong file đa-UC |
16
+ | **Code** (chỗ chưa implement) | `@trace.stub` · `@trace.stub_owner` · `@trace.stub_for` · `@trace.seam_pending` · `@trace.seam_port` |
17
+ | **Test** | `@trace.verifies` |
18
+ | **Bug fix** | `@trace.fixes` · `@trace.root_cause` · `@trace.regression` |
19
+
20
+ → Đầy đủ field & format: [Reference › Trace Schema](../04-reference/trace-schema.md).
21
+
22
+ ---
23
+
24
+ ## Boundary-only tagging
25
+
26
+ Chỉ tag `@trace` ở **boundary**, không tag mọi file → tránh **tag explosion**:
27
+
28
+ | ✅ Tag | ❌ Không tag |
29
+ |--------|-------------|
30
+ | Controller / Handler / Middleware / Steps file | Entity / Repository / DTO / Interface / Base class |
31
+
32
+ > Shared code (entity, repo) được dò qua **import chain** từ boundary — không cần tag riêng.
33
+
34
+ ---
35
+
36
+ ## Trace state — file `.tsv`
37
+
38
+ `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` — mỗi UC × platform một sổ. Trong umbrella, nằm ở **spec repo dùng chung** (một nơi authoritative để PM/PO quản lý).
39
+
40
+ | Cột | Chủ sở hữu | Ý nghĩa |
41
+ |-----|-----------|---------|
42
+ | `status` | `/generate-code`, `/validate-traces` | OK / GAP / DRIFT / UNTRACKED |
43
+ | `implemented_by` | `/generate-code` | File code hiện thực SC |
44
+ | `dev_selftest` | `/dev-run-test` | Smoke của **dev** |
45
+ | `qc_status` | `/qc-run-test`, `/report-bug` | Trạng thái QC **chính thức** (Playwright) |
46
+ | `bdd_version` / `spec_ver` | spec | Version để phát hiện drift |
47
+ | `service` *(cột 23)* | `/generate-bdd` | Đội/submodule sở hữu SC — nguồn của `by_service` trên dashboard |
48
+ | `design_spec_version` *(cột 24)* | `/generate-bdd` | Version design-spec lúc sinh BDD *(FE/App; `—` cho backend)* |
49
+
50
+ **24 cột.** TSV cũ thiếu cột mới → đọc thành giá trị rỗng, **không báo lỗi**; header tự nâng ở lần `/generate-bdd` gen lại kế tiếp. Đọc theo **tên cột ở header row**, không theo vị trí.
51
+
52
+ > **Làm mất hiệu lực ≠ ghi đè.** Chủ sở hữu là người **duy nhất** ghi giá trị **khẳng định** (`pass`/`fail`/số lượng). Nhưng lệnh nào làm giá trị đó **hết đúng** (spec đổi, code đổi) **bắt buộc** hạ nó về `not_run`/`—`. Giữ một `pass` sinh ra từ spec đã bị sửa là **báo cáo sai**, không phải tôn trọng quyền sở hữu cột. Ngoại lệ có chủ ý: `qc_owner`/`qc_blocked_by` (con trỏ bug vẫn còn giá trị) và `test_count`/`test_classes` (test vẫn trên đĩa — **cảnh báo**, không hạ số, để tỷ lệ coverage không nhảy loạn).
53
+ | `gen_ver` | `/generate-code` | Version lúc sinh code (so với `spec_ver`) |
54
+ | `test_count` | test | Số test phủ SC |
55
+ | `last_updated` | nhiều | Mốc cập nhật |
56
+
57
+ > **`dev_selftest` ≠ `qc_status`.** Dev smoke (nhanh, tự kiểm) và QC chính thức (Playwright, evidence) là **hai trục độc lập** — không lấn quyền nhau.
58
+
59
+ ---
60
+
61
+ ## Phân loại coverage (Coverage Status)
62
+
63
+ `/validate-traces` phân loại mỗi SC theo **thứ tự ưu tiên** (rule sớm thắng):
64
+
65
+ | # | Trạng thái | Điều kiện | Hành động |
66
+ |---|-----------|-----------|-----------|
67
+ | 1 | **UNTRACKED** | `gen_ver == —` | Chưa sinh code → `/generate-code` |
68
+ | 2 | **DRIFT** | có code **và** `spec_ver != gen_ver` | Spec đổi → **regen trước khi test** |
69
+ | 3 | **GAP** | có code **và** `test_count == — / 0` | Có code, chưa test → bù test |
70
+ | 4 | **OK** | version khớp, có code, có test | Đủ phủ |
71
+
72
+ > **DRIFT xét trước GAP:** SC có code + chưa test + 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.
73
+
74
+ ---
75
+
76
+ ## Version sống ở đâu — và vì sao code CŨNG mang version
77
+
78
+ **Spec là SSOT của "version hiện tại". Code mang version của "lúc tôi được sinh ra".** Hai thứ khác nhau, nên không phải dual SSOT.
79
+
80
+ | Nơi | Ghi cái gì | Ai ghi |
81
+ |---|---|---|
82
+ | `.feature` / PRD / tech-doc | version **hiện tại** của spec — SSOT | tác giả spec |
83
+ | `.tsv` `spec_ver` | gương của `@trace.sc_version` hiện tại | `/generate-bdd`, `/validate-traces` |
84
+ | `.tsv` `gen_ver` | version scenario **tại thời điểm codegen**, theo từng SC | `/generate-code` |
85
+ | **Code** `@trace.prd_version` · `@trace.bdd_version` · `@trace.tech_doc_revision` · `@trace.design_spec_version` | version của **từng artifact upstream** tại thời điểm codegen, theo từng **method** | `/generate-code` |
86
+
87
+ Drift = **so các mốc này với nhau**; sự lệch nhau chính là tín hiệu, không phải lỗi dữ liệu:
88
+
89
+ - `spec_ver != gen_ver` → `DRIFT` (scenario đổi sau khi sinh code)
90
+ - `@trace.prd_version` trong code < Version PRD hiện tại → `PRD_DRIFT`
91
+ - `@trace.bdd_version` trong code < `.feature` hiện tại → `BDD_DRIFT`
92
+ - `@trace.tech_doc_revision` trong code < `@trace.revision` của tech-doc → `TECHDOC_DRIFT`
93
+ - `@trace.design_spec_version` trong code FE < Version design-spec → `DESIGNSPEC_DRIFT`
94
+
95
+ > **Lệch version KHÔNG luôn là drift.** PRD và tech-doc là tài liệu **gộp** phủ nhiều UC nhưng chỉ có **một** số version. Thêm UC7 làm mọi UC cũ lệch số dù không đổi một chữ. Nên `/validate-traces` **lọc theo `{changelog_scope}` của row changelog**: UC có trong tập bị ảnh hưởng → `PRD_DRIFT` 🟠; không có → `PRD_STALE_REF` ⓘ (chỉ con trỏ cũ, sạch bằng `--realign-prd-version`); row **mơ hồ** → 🟠 cho mọi UC (lưới an toàn).
96
+ >
97
+ > Dòng changelog là **contract máy đọc** (`changelog_row_contract`), không phải ghi chú cho người đọc: mỗi mệnh đề mở đầu bằng **đơn vị sở hữu** (`{UC-ID}:` hoặc `PRD-global:`), **BR/AC luôn đi kèm UC sở hữu** — `sửa BR8` trơ trọi nêu đủ ID để **không** bị coi là mơ hồ, nhưng phép thử là *"**UC** này có trong tập?"*, nên UC sở hữu BR8 rơi vào ⓘ trong khi nội dung của nó vừa đổi, và `--realign` dán nhãn lại (GAPS-v4 G53). Consumer vì thế **chuẩn hoá BR/AC về UC sở hữu** trước khi so. `self-check` **R12** canh cả bốn producer.
98
+
99
+ > **Và một điểm so-version KHÔNG bắt được: sửa tay.** Mọi cờ trên so **nhãn**, không so **nội dung** — không content hash nào trong framework. PRD bị sửa `Version` không đổi **0 cờ**. `/validate-traces` **Step 3.9** bịt bằng cờ 🔴 `PRD_UNTRACKED_EDIT`: so `git diff` **và** `git status` với mốc `spec_baseline` của lần audit trước. Cửa chính để đổi một yêu cầu đã duyệt là **`/amend-prd`**.
100
+
101
+ ** sao không thể bỏ tag version trong code chỉ dựa vào `.tsv`:**
102
+
103
+ 1. **Độ phân giải khác nhau.** `.tsv` một sổ cho mỗi UC × platform. Một **file code** thể phục vụ nhiều UC, mỗi UC một version khác nhau chỉ tag đặt cạnh từng method mới diễn đạt được "UC1 bdd v1.4, UC3 v2.1".
104
+ 2. **Vòng đời khác nhau.** `.tsv` là artifact **sinh ra**, có thể regen/xoá/mirror; ở chế độ umbrella nó còn nằm ở **repo khác** (spec submodule) với code. Tag trong code là bản ghi duy nhất **đi cùng** code qua mọi lần copy/move/merge.
105
+ 3. **Sự lệch nhau là thứ ta muốn đo.** Nếu chỉ có một bản ghi thì không có gì để so — đó mới là lúc drift trở nên không phát hiện được.
106
+
107
+ > ⚠️ **Đừng "tối ưu" bằng cách gỡ tag version khỏi code.** `/validate-traces` Step 4/5/5c **đọc chính các tag đó**; gỡ đi là làm drift detection mù **im lặng** — build vẫn xanh, dashboard vẫn đẹp. `/review-code` lăng kính 1 gắn cờ **major** cho mỗi block `@trace.implements` thiếu tag version đi kèm.
108
+
109
+ ---
110
+
111
+ ## Luồng truy vết (Trace Flow)
112
+
113
+ ```mermaid
114
+ flowchart LR
115
+ PRD["PRD<br/>prd_version"] --> BDD["Scenario<br/>@trace.id + bdd_version"]
116
+ BDD --> CODE["Code boundary<br/>@trace.implements/source"]
117
+ CODE --> TEST["Test<br/>@trace.verifies"]
118
+ BDD -.-> TSV[".tsv state<br/>status/gen_ver/qc_status"]
119
+ CODE -.-> TSV
120
+ TEST -.-> TSV
121
+ TSV --> VM["/validate-traces<br/>Coverage Matrix"]
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Sổ trace trong git — và khi nó conflict
127
+
128
+ Sổ trace là **dữ liệu không dựng lại được**, nằm trong git, và **được nhiều người ghi trên
129
+ nhiều nhánh song song**. Ba thứ đó cộng lại nghĩa git phải được dạy cách merge nó.
130
+
131
+ ### Luật đã cài sẵn
132
+
133
+ `/setup-ai-first` tạo `{trace_dir}/.gitattributes`; `/sync` Step 4c kiểm và tạo hộ nếu thiếu:
134
+
135
+ ```gitattributes
136
+ *.tsv text eol=lf merge=union
137
+ *.jsonl text eol=lf merge=union
138
+ ```
139
+
140
+ | Luật | Không có nó thì sao |
141
+ |---|---|
142
+ | `merge=union` | Hai nhánh cùng ghi một sổ → **conflict**. Giải bằng "take mine" = **mất row của người kia, im lặng**. Với `trace-history.jsonl` (append cuối file) thì **mọi** cặp nhánh song song đều conflict. |
143
+ | `text eol=lf` | Một máy ghi CRLF git thấy **mọi dòng** đã đổi → union giữ cả hai bản → **nhân đôi cả file**, gồm cả dòng header. Team mixed Windows/macOS gặp ca này mà không ai làm gì sai. |
144
+
145
+ `union` driver **built-in** của git — không ai cần chạy `git config` thêm.
146
+
147
+ > **`*.json` cố ý KHÔNG trong danh sách.** `trace-report.json` nằm cùng thư mục và union
148
+ > trên JSON tạo ra **JSON không hợp lệ** → panel VS Code parse lỗi. Nó **sinh lại được**:
149
+ > conflict đó thì chạy lại `/validate-traces`, đừng merge tay.
150
+
151
+ ### Đánh đổi có chủ ý: trùng row thay vì mất row
152
+
153
+ `merge=union` **thể** tạo hai row cùng `sc_id`. Đó **thiết kế**, không phải lỗi:
154
+
155
+ ```
156
+ trùng row → --lint-trace T4 bắt được → /validate-traces reconcile → sạch
157
+ mất row → KHÔNG bắt được → phát hiện sau 3 tuần → khôi phục bằng tay
158
+ ```
159
+
160
+ Đây là lý do luật merge và `--lint-trace` là **một cặp**: union chuyển lỗi từ dạng *im lặng*
161
+ sang dạng *bắt được*, cái bắt phải tồn tại. union không có lint thì chỉ là đổi chỗ lỗi.
162
+
163
+ ### Playbook 4 bước
164
+
165
+ Vẫn thấy conflict trong `{trace_dir}/` (nhánh phân kỳ quá xa, hoặc luật vừa mới được thêm):
166
+
167
+ 1. **GIỮ CẢ HAI BÊN.** Xoá ba dòng marker (`<<<<<<<`, `=======`, `>>>>>>>`), giữ toàn bộ row
168
+ của cả hai phía. **Đừng chọn một bên.**
169
+ 2. `npx @educa-corp/sdd-framework --lint-trace` — T7 xác nhận không còn marker, T4 chỉ ra row nào trùng.
170
+ 3. `/validate-traces` — reconcile row trùng về một row đúng, tính lại `status`.
171
+ 4. Commit.
172
+
173
+ **Ba điều không bao giờ làm:**
174
+
175
+ | | sao |
176
+ |---|---|
177
+ | `git checkout --ours/--theirs` trên file trace | Xoá sạch row của một phía. Không có gì báo. |
178
+ | Xoá file trace để "cho sạch" rồi chạy lại pipeline | Sổ **không regenerate được** — `trace-history.jsonl` mất là mất vĩnh viễn. |
179
+ | Commit khi còn marker | Marker thành một "row" TSV. `--lint-trace` T7 bắt, nhưng nếu chưa cắm vào CI thì nó vào nhánh chung. |
180
+
181
+ ---
182
+
183
+ ## Đọc tiếp (Next)
184
+
185
+ - [Architecture](architecture.md) — 3 lớp & context-loader
186
+ - [Pipeline › Validate Traces](pipeline-steps/09-validate-traces.md) — dùng ma trận coverage
187
+ - [Reference › Trace Schema](../04-reference/trace-schema.md) — field đầy đủ
@@ -98,7 +98,7 @@ sprint thứ ba không ai làm.** Framework có hai lệnh CLI trả exit code
98
98
 
99
99
  | Lệnh | Chặn gì | Đặt ở đâu |
100
100
  |---|---|---|
101
- | `--lint-trace` | **Cấu trúc sổ**: header lệch · row sai số ô · enum sai · `sc_id` trùng · marker conflict git · `.jsonl` hỏng. Cộng hai điều kiện **cấu hình** ở mức ⚠️: thiếu luật merge · sổ bị gitignore | pre-push **và** CI |
101
+ | `--lint-trace` | **Cấu trúc sổ** (12 rule): header lệch · row sai số ô · enum sai · `sc_id` trùng · marker conflict git · `.jsonl` hỏng. Cộng **T12 — nhất quán GIỮA các ô**: row vừa `status ∈ {DRIFT, ORPHANED}` vừa mang `dev_selftest`/`qc_status = pass`. Cộng hai điều kiện **cấu hình** ở mức ⚠️: thiếu luật merge · sổ bị gitignore | pre-push **và** CI |
102
102
  | `--gate-trace` | **Cấu hình** (nâng hai ⚠️ trên thành chặn) + **cờ 🔴**: `ORPHANED` · `TRACE_ORPHAN` · `SEAM_UNWIRED` · `STUB_UNRESOLVED` | CI (cần report tươi) |
103
103
 
104
104
  ```bash
@@ -113,13 +113,22 @@ Mẫu sẵn dùng: `.agent/templates/ci/trace-gate.yml` (GitHub Actions) · `.ag
113
113
 
114
114
  0. **Sổ được bảo vệ?** — sổ có **nằm trong git**? git có **biết cách gộp** sổ? Kiểm cấu trúc của một quyển sổ sắp mất thì vô nghĩa. Hai điều kiện này `lint-trace` đã phát hiện dưới dạng ⚠️; gate **nâng** chúng thành lỗi chặn — *pre-push nhắc, CI chặn*.
115
115
  1. **Sổ đúng hình dạng?** (gọi `--lint-trace`) — phán trạng thái trên sổ lệch cột là phán trên dữ liệu rác.
116
- 2. **Report còn tươi?** — đối chiếu `trace-report.json` với chính sổ TSV nó khai là đang mô tả.
117
- Không có tầng này thì cổng là **sân khấu**: chạy `/validate-traces` một lần, commit report,
118
- rồi sửa gì cũng được — CI đọc report cũ và cho qua mãi.
116
+ 2. **Report còn tươi VÀ phủ toàn bộ?** — đối chiếu `trace-report.json` với chính sổ TSV nó khai
117
+ là đang mô tả. Không có tầng này thì cổng là **sân khấu**: chạy `/validate-traces` một lần,
118
+ commit report, rồi sửa gì cũng được — CI đọc report cũ và cho qua mãi.
119
+ **Cộng thêm (G57):** report mang field `scope`, và G2 **fail** nếu `scope.kind !== "all"` —
120
+ **không ngoại lệ**, không đếm xem trên đĩa có bao nhiêu domain. `/validate-traces --domain/--prd/--uc`
121
+ là audit **một phần**; muốn tạo PR thì phải có một lần audit **toàn bộ** đã commit.
122
+ *(Report sinh trước G57 không có `scope` → gate ⚠️ "kiểm độ phủ ở mức YẾU", không fail.)*
119
123
  3. **Có cờ 🔴?** — đếm counter, nêu tên thủ phạm kèm câu `fix` của chính framework.
120
124
 
121
125
  ### Giới hạn — nói rõ với team, đừng để họ tin quá
122
126
 
127
+ > **Hai thứ `--lint-trace` bắt được mà không cần LLM** *(nên cứ để nó chạy ở CI)*:
128
+ > **T12** — `status = DRIFT` mà `dev_selftest = pass` là một sổ **hợp lệ** với 11 rule cũ (T1–T8
129
+ > chỉ kiểm hình dạng *từng ô*), nhưng nó là một lời khẳng định **sai**. T12 là rule đầu tiên nhìn
130
+ > **nhiều ô cùng lúc**. **T10/T11** — luật merge + gitignore, gate nâng thành chặn.
131
+ >
123
132
  > `--gate-trace` chứng minh **"report khớp SỔ"**.
124
133
  > Chỉ `/validate-traces` chứng minh được **"sổ khớp CODE"** (nó phải quét tag trong source,
125
134
  > đọc `.feature`, so version — việc của LLM).
@@ -81,6 +81,7 @@ public TokenDto login(...) { }
81
81
  - ❌ Gộp tag của nhiều UC về một header file, hoặc trỏ `@trace.source` vào thư mục → drift báo oan hoặc mù; UC rơi về `UNTRACKED` dù đã có code.
82
82
  - ❌ Gỡ tag version khỏi code cho "gọn" → `/validate-traces` mù, **im lặng**.
83
83
  - ❌ Coi `dev_selftest` thay QC chính thức.
84
+ - ❌ Chạy `/dev-run-test` khi row đang `DRIFT` rồi tin dấu xanh. Từ v0.7.0 lệnh **tự chặn**: test pass trên row `DRIFT` → nó ghi `not_run`, **không** ghi `pass` (`fail` thì vẫn ghi `fail`). Lý do: `pass` nghĩa *"đã nghiệm thu theo spec **hiện tại**"*, và test cũ đang nghiệm thu một hành vi không còn tồn tại. Đường đúng: `/generate-code {UC-ID}` → `/dev-gen-test {UC-ID}` → chạy lại.
84
85
  - ❌ Để AI tự review code nó vừa sinh.
85
86
  - ❌ Tạo PR khi `/validate-traces` còn cờ 🔴 (`SEAM_UNWIRED` · `STUB_UNRESOLVED` · `ORPHANED` · `TRACE_ORPHAN`) — build xanh không chứng minh luồng ghép chạy đúng.
86
87
  - ❌ Coi FE `fe_phase = ui` là xong vì status đã `OK` — test đang chạy trên **mock**.
@@ -1,72 +1,89 @@
1
- [← Docs Home](../README.md) · [Guides](./)
2
-
3
- # Guide · Product Owner / BA
4
-
5
- > Bạn **định nghĩa cái gì đáng làm**. Vai trò của bạn nặng nhất ở **thượng nguồn** (Discovery → PRD → BDD) — nơi sai một ly đi một dặm.
6
-
7
- ---
8
-
9
- ## Chuỗi bước của bạn (Your path)
10
-
11
- ```mermaid
12
- flowchart LR
13
- A["/define-product<br/>🟢 Lead"] --> B["/generate-prd<br/>🟢 Lead"]
14
- B2["/extend-prd<br/>🟢 Lead — PRD đã có"] --> C
15
- B --> C["/refine-prd<br/>🟢 accept findings"]
16
- C --> D["/review-context PRD<br/>🔒 approve"]
17
- D --> E["/generate-design-spec<br/>🟡 review (FE/App)"]
18
- E --> F["/generate-bdd<br/>🟢 UC decomposition"]
19
- F --> G["/review-context BDD<br/>🔒 approve"]
20
- ```
21
-
22
- Sau khi BDD `approved`, bạn bàn giao xuống Dev/SA — nhưng vẫn nhận **product-gap** từ QC.
23
-
24
- ---
25
-
26
- ## Việc của bạn ở mỗi bước
27
-
28
- | Bước | Bạn làm gì | Quyết định |
29
- |------|-----------|------------|
30
- | [Discovery](../02-concepts/pipeline-steps/01-discovery.md) | Trả lời Q&A 8 chặng, **chốt từng chặng** | Vấn đề, user, UC, BR, AC, edge case, scope |
31
- | [Specification](../02-concepts/pipeline-steps/02-specification.md) | Duyệt PRD draft; **accept/reject từng finding** của `/refine-prd`; đặt `Status: approved` | Scope & terminology đúng chưa |
32
- | [Design-Spec](../02-concepts/pipeline-steps/03-design-spec.md) | Review spec visual bám Figma (FE/App) | Visual khớp intent |
33
- | [BDD](../02-concepts/pipeline-steps/04-bdd.md) | Chốt **UC decomposition**; đặt `@trace.status: approved` | Cấu trúc UC/SC đúng |
34
- | [QC](../02-concepts/pipeline-steps/08-qc-automation.md) | Nhận **product-gap**, quyết ưu tiên sửa | Gap nào lỗi sản phẩm |
35
-
36
- ---
37
-
38
- ## Nguyên tắc sống còn cho PO
39
-
40
- 1. **Viết thuần ngôn ngữ nghiệp vụ** — đừng nhét API/retry/timeout vào PRD/BDD. Business Language Guard sẽ chặn, nhưng bạn nên tự giữ altitude.
41
- 2. **Bốn ngăn không lộn**: AC (nghiệm thu) · BR/BL (cơ chế) · Scope (ranh giới) · Dictionary (định nghĩa).
42
- 3. **Gate trạng thái, không phải lệnh** — "duyệt" = bạn tự đặt `| Status | approved |`. Chỉ đặt khi **sạch finding critical**.
43
- 4. **Chốt từng chặng, đừng "để AI tự hiểu"** — AI sẽ suy diễn và bạn trả giá ở downstream.
44
- 5. Khi bạn sửa cùng một kiểu nhiều lần → gợi ý team `/learn` để ghi lesson.
45
-
46
- ---
47
-
48
- ## Câu hỏi bạn cần trả lời được
49
-
50
- - Tính năng này giải quyết pain point gì? Cho ai?
51
- - Gồm những UC/BR/AC nào? Edge case nào?
52
- - Cái gì **trong** scope, cái gì **ngoài**?
53
- - Mỗi scenario BDD có phủ đúng một AC/BR không?
54
-
55
- ---
56
-
57
- ## Anti-pattern
58
-
59
- - Đặt `approved` khi còn finding critical phá gate, code rác.
60
- - Bỏ `/refine-prd` "vì PRD trông ổn".
61
- - ❌ Chạy `/generate-prd` lại trên PRD đã có để "cập nhật" — nó **từ chối chạy**, và đúng vậy: ghi đè sẽ mất changelog + đánh số lại BR (phá liên kết ở mọi `.feature` đã sinh). Thêm yêu cầu thì dùng **`/extend-prd`**.
62
- - ❌ Viết dòng changelog kiểu `"cập nhật theo yêu cầu mới"` — dòng đó là **contract**. Mơ hồ thì `/generate-bdd` gen lại **toàn bộ**, và `/validate-traces` báo động oan cho **mọi** UC thay vì chỉ UC vừa đổi. Luôn nêu **UC/AC/BR bị ảnh hưởng**.
63
- - ❌ Để `feedback/prd-change-requests/` chất đống — đó là yêu cầu thật tester phát hiện từ sản phẩm chạy thật, và **không cờ trace nào bắt được** (chưa có AC thì theo mọi thước đo coverage nó *không tồn tại*). `/validate-traces` nhắc kèm số ngày chờ; xử bằng `/extend-prd`.
64
- - Nhảy từ ý tưởng thẳng sang yêu cầu Dev code.
65
-
66
- ---
67
-
68
- ## Lệnh của bạn (Your commands)
69
-
70
- `/define-product` · `/generate-prd` · `/extend-prd` · `/refine-prd` · `/review-context` · `/generate-design-spec` · `/generate-bdd`
71
-
72
- → [Bảng lệnh đầy đủ](../04-reference/commands.md) · [Glossary](../02-concepts/glossary.md)
1
+ [← Docs Home](../README.md) · [Guides](./)
2
+
3
+ # Guide · Product Owner / BA
4
+
5
+ > Bạn **định nghĩa cái gì đáng làm**. Vai trò của bạn nặng nhất ở **thượng nguồn** (Discovery → PRD → BDD) — nơi sai một ly đi một dặm.
6
+
7
+ ---
8
+
9
+ ## Chuỗi bước của bạn (Your path)
10
+
11
+ ```mermaid
12
+ flowchart LR
13
+ A["/define-product<br/>🟢 Lead"] --> B["/generate-prd<br/>🟢 Lead"]
14
+ B2["/extend-prd<br/>🟢 Lead — THÊM vào PRD đã có"] --> C
15
+ B3["/amend-prd<br/>🟢 Lead — ĐỔI yêu cầu đã có"] --> C
16
+ B --> C["/refine-prd<br/>🟢 accept findings"]
17
+ C --> D["/review-context PRD<br/>🔒 approve"]
18
+ D --> E["/generate-design-spec<br/>🟡 review (FE/App)"]
19
+ E --> F["/generate-bdd<br/>🟢 UC decomposition"]
20
+ F --> G["/review-context BDD<br/>🔒 approve"]
21
+ ```
22
+
23
+ Sau khi BDD `approved`, bạn bàn giao xuống Dev/SA — nhưng vẫn nhận **product-gap** từ QC.
24
+
25
+ ### Bốn nhánh chạm PRD — phân biệt bằng THAO TÁC GHI
26
+
27
+ | Bạn muốn | Lệnh | Ghi kiểu gì |
28
+ |---|---|---|
29
+ | PRD **chưa có** | `/generate-prd` | **Write** cả file |
30
+ | **THÊM** UC/AC/BR mới | `/extend-prd` | Edit **add-only** output **superset chặt**, đánh số **nối tiếp** |
31
+ | **ĐỔI** một yêu cầu đang đúng cú pháp *("BR8 nói tối đa 5 file, giờ đổi thành 20")* | **`/amend-prd`** | Edit **tại chỗ** output **KHÔNG** phải superset; bạn khai tường minh ID cần sửa |
32
+ | Sửa **vấn đề review chỉ ra** | `/refine-prd` Review Board `--resume` | Edit trong phạm vi finding |
33
+
34
+ **Bỏ hẳn một quy tắc** → `/amend-prd --retire {ID}`: khai tử **tại chỗ**, **giữ nguyên** row + ID. Không có lệnh xoá row, và có chủ ý — xoá làm `@trace.business_rules` trong `.feature` trỏ vào ID không còn ⇒ `TRACE_ORPHAN` 🔴.
35
+
36
+ > ⚠️ **Đừng sửa tay file `.md`** *(GAPS-v4 G54)*. Mọi cờ drift của framework so **nhãn version**, không so **nội dung** — nên sửa tay mà không bump version là điểm mù **tuyệt đối**: `/validate-traces` thấy version khớp ⇒ sạch · gate thấy report khớp sổ ⇒ PASS · CI thấy PR không chạm code ⇒ không đòi audit. Ba tầng xanh trên một yêu cầu code chưa hề làm theo.
37
+ >
38
+ > `/validate-traces` Step 3.9 canh cửa sau bằng cờ 🔴 `PRD_UNTRACKED_EDIT` (so `git diff` **và** `git status` với mốc lần audit trước). Đường sửa: bump `Version` + ghi một row changelog nêu UC — tức đúng việc `/amend-prd` làm hộ.
39
+
40
+ ---
41
+
42
+ ## Việc của bạn mỗi bước
43
+
44
+ | Bước | Bạn làm | Quyết định |
45
+ |------|-----------|------------|
46
+ | [Discovery](../02-concepts/pipeline-steps/01-discovery.md) | Trả lời Q&A 8 chặng, **chốt từng chặng** | Vấn đề, user, UC, BR, AC, edge case, scope |
47
+ | [Specification](../02-concepts/pipeline-steps/02-specification.md) | Duyệt PRD draft; **accept/reject từng finding** của `/refine-prd`; đặt `Status: approved` | Scope & terminology đúng chưa |
48
+ | [Design-Spec](../02-concepts/pipeline-steps/03-design-spec.md) | Review spec visual bám Figma (FE/App) | Visual khớp intent |
49
+ | [BDD](../02-concepts/pipeline-steps/04-bdd.md) | Chốt **UC decomposition**; đặt `@trace.status: approved` | Cấu trúc UC/SC đúng |
50
+ | [QC](../02-concepts/pipeline-steps/08-qc-automation.md) | Nhận **product-gap**, quyết ưu tiên sửa | Gap nào là lỗi sản phẩm |
51
+
52
+ ---
53
+
54
+ ## Nguyên tắc sống còn cho PO
55
+
56
+ 1. **Viết thuần ngôn ngữ nghiệp vụ** — đừng nhét API/retry/timeout vào PRD/BDD. Business Language Guard sẽ chặn, nhưng bạn nên tự giữ altitude.
57
+ 2. **Bốn ngăn không lộn**: AC (nghiệm thu) · BR/BL (cơ chế) · Scope (ranh giới) · Dictionary (định nghĩa).
58
+ 3. **Gate là trạng thái, không phải lệnh** — "duyệt" = bạn tự đặt `| Status | approved |`. Chỉ đặt khi **sạch finding critical**.
59
+ 4. **Chốt từng chặng, đừng "để AI tự hiểu"** AI sẽ suy diễn và bạn trả giá ở downstream.
60
+ 5. Khi bạn sửa cùng một kiểu nhiều lần → gợi ý team `/learn` để ghi lesson.
61
+
62
+ ---
63
+
64
+ ## Câu hỏi bạn cần trả lời được
65
+
66
+ - Tính năng này giải quyết pain point gì? Cho ai?
67
+ - Gồm những UC/BR/AC nào? Edge case nào?
68
+ - Cái **trong** scope, cái gì **ngoài**?
69
+ - Mỗi scenario BDD có phủ đúng một AC/BR không?
70
+
71
+ ---
72
+
73
+ ## Anti-pattern
74
+
75
+ - ❌ Đặt `approved` khi còn finding critical → phá gate, code rác.
76
+ - ❌ Bỏ `/refine-prd` "vì PRD trông ổn".
77
+ - ❌ Chạy `/generate-prd` lại trên PRD đã có để "cập nhật" — nó **từ chối chạy** (§Guard: *"Tồn tại → DỪNG. KHÔNG ghi, KHÔNG hỏi Y/N"*), và đúng vậy: ghi đè sẽ mất changelog + đánh số lại BR (phá liên kết ở mọi `.feature` đã sinh). **Thêm** yêu cầu → `/extend-prd`; **đổi** một yêu cầu đã có → `/amend-prd`.
78
+ - ❌ Mở file PRD `.md` ra sửa tay — xem cảnh báo G54 ở §Chuỗi bước. Framework **không thấy** thay đổi đó cho tới khi `/validate-traces` Step 3.9 bắt được, và mọi cờ drift ở giữa đều báo sạch.
79
+ - ❌ Viết dòng changelog kiểu `"cập nhật theo yêu cầu mới"` — dòng đó là **contract**. Mơ hồ thì `/generate-bdd` gen lại **toàn bộ**, và `/validate-traces` báo động oan cho **mọi** UC thay vì chỉ UC vừa đổi. Luôn nêu **UC/AC/BR bị ảnh hưởng**.
80
+ - ❌ Để `feedback/prd-change-requests/` chất đống — đó là yêu cầu thật tester phát hiện từ sản phẩm chạy thật, và **không cờ trace nào bắt được** (chưa có AC thì theo mọi thước đo coverage nó *không tồn tại*). `/validate-traces` nhắc kèm số ngày chờ; xử bằng `/extend-prd`.
81
+ - ❌ Nhảy từ ý tưởng thẳng sang yêu cầu Dev code.
82
+
83
+ ---
84
+
85
+ ## Lệnh của bạn (Your commands)
86
+
87
+ `/define-product` · `/generate-prd` · `/extend-prd` · `/refine-prd` · `/review-context` · `/generate-design-spec` · `/generate-bdd`
88
+
89
+ → [Bảng lệnh đầy đủ](../04-reference/commands.md) · [Glossary](../02-concepts/glossary.md)