@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
@@ -65,6 +65,40 @@ Ba mức, định nghĩa đầy đủ ở `steps/gate.md` Bước 3a — **đây
65
65
  **Ngoại lệ có chủ ý:** `qc_owner`/`qc_blocked_by` (con trỏ tới bug — spec đổi không làm bug biến
66
66
  mất) và `test_count`/`test_classes` (test vẫn tồn tại trên đĩa; số lượng không sai, chỉ nội dung
67
67
  cũ → **cảnh báo**, không hạ số, để tỷ lệ coverage không nhảy loạn).
68
+ - **Sửa spec phải đi qua một lệnh.** Mọi drift detector so **nhãn version**, không so **nội dung**
69
+ (0 content hash trong toàn bộ codebase) — nên một PRD/tech-doc bị sửa tay mà không bump version là
70
+ điểm mù **tuyệt đối**: cả `/validate-traces`, `gate-trace`, và `require-fresh-audit` đều xanh, và
71
+ cả ba **đúng theo định nghĩa của chính chúng**. Bốn cửa chính: `/generate-prd` (mới) ·
72
+ `/extend-prd` (**thêm**) · **`/amend-prd`** (**đổi**) · `/refine-prd`/`/review-context --resume`
73
+ (áp finding). `/validate-traces` Step 3.9 canh cửa sau bằng cờ 🔴 `PRD_UNTRACKED_EDIT`
74
+ (`spec_edit_detection`: git diff **và** git status vs mốc `spec_baseline`).
75
+ *Đường ra cố ý **tự lành**, không có `--accept-edit`: bump version + ghi row changelog nêu UC là
76
+ hết cờ. Một cờ escape sẽ là một đường dán nhãn lên thay đổi chưa ai xem — đúng cái ba rào của
77
+ `--realign` tồn tại để chặn.*
78
+ - **Làm mất hiệu lực có MỆNH ĐỀ ĐỐI NGẪU: ai KHẲNG ĐỊNH một giá trị dương phải được phép khẳng
79
+ định.** Luật ngay trên nói *"ai làm giá trị hết đúng thì phải hạ nó"* — đúng, và được thực thi tốt.
80
+ Nhưng thiếu nửa này thì chuỗi thành **hạ xuống → dựng lại**: `/generate-bdd` hạ
81
+ `dev_selftest → not_run` khi spec đổi, rồi `/dev-run-test` (lệnh kế tiếp trong vòng lặp dev bình
82
+ thường) ghi lại `pass` kèm **ngày hôm nay** vì test cũ + code cũ vẫn xanh.
83
+ `pass` **không** mang nghĩa *"test đã chạy xanh"* — nó mang nghĩa *"scenario này đã được nghiệm thu
84
+ theo spec **hiện tại**"*. Trên row `DRIFT` nghĩa thứ nhất đúng và nghĩa thứ hai **sai**. Nên `status`
85
+ trực giao với **kết quả chạy**, **KHÔNG** trực giao với **quyền khẳng định**.
86
+ Contract: `bin/trace-schema.json` → `positive_assertion_guards`; `self-check` **R14** canh chủ cột
87
+ thực sự rẽ nhánh theo `status`, `lint-trace` **T12** bắt trạng thái ở sổ thật bất kể ai ghi.
88
+ **`fail` không bao giờ bị chặn** — đây là guard chống *báo cáo sai*, không phải guard *che tin xấu*.
89
+ - **Dòng changelog là contract máy đọc, không phải ghi chú cho người đọc.** PRD và tech-doc gộp
90
+ đều phủ nhiều UC nhưng chỉ có **một** nhãn version, nên `/validate-traces` Step 4/5 lọc 🟠 `*_DRIFT`
91
+ vs ⓘ `*_STALE_REF` **bằng chính dòng đó**. Grammar khai ở `bin/trace-schema.json` →
92
+ `changelog_row_contract`; `self-check` **R12** fail build nếu lệch. Ba luật:
93
+ **(1)** mỗi mệnh đề mở đầu bằng **đơn vị sở hữu** — `{UC-ID}:` hoặc `PRD-global:`/`doc-global:`;
94
+ **(2)** BR/AC **luôn đi kèm UC sở hữu** (`UC3: sửa BR8`), **không bao giờ đứng một mình** —
95
+ consumer khớp theo UC, nên `sửa BR8` trơ trọi làm UC3 bị xếp ⓘ trong khi BR8 vừa đổi hành vi, và
96
+ `--realign-prd-version` (chỉ chặn 🟠) sẽ dán nhãn version lại lên đó;
97
+ **(3)** hậu tố `[no-behavior]` **chỉ** cho thay đổi mà producer **chứng minh được** là không đổi
98
+ hành vi (`changelog_row_contract.neutral_checks`) — không dành cho người tự khai.
99
+ *Lưới an toàn "row mơ hồ → 🟠 cho MỌI UC" đúng khi **thiếu** thông tin, và sai khi producer **có**
100
+ thông tin mà không ghi: đó là G52 — `/review-context --fix` từng ghi cứng một dòng 0 scope trong
101
+ khi findings YAML của nó có `uc_id` bắt buộc cho từng finding.*
68
102
  - **Mỗi audit flag phải quan sát được ở CẢ BA tầng.** Mọi giá trị trong
69
103
  `vocabularies.audit_flags` bắt buộc có đủ: **(1)** một counter `{flag_lowercase}_count`
70
104
  trong Step 7 + `summary` của `trace-report.json` · **(2)** một mảng trong `issues` ·
@@ -161,11 +161,25 @@ services:
161
161
 
162
162
  *(Cả 2a/2b/2c: override `paths.specs_dir`/`paths.tech_docs_dir` per-service CHỈ khi `setup.spec_source` KHÔNG được đặt. Khi `spec_source` ĐƯỢC đặt, MỌI BDD/tech-doc là artifact liên team → để bước 4 route sang spec repo; KHÔNG pin per-service ở đây.)*
163
163
 
164
- **3. Fallback**:
165
- - Không phát hiện được domain, hoặc domain không khớp key nào trong `services` → giữ path mặc định từ Bước 1, đặt `active_service = unresolved`.
166
- - Domain khớp một map-theo-platform (2b) nhưng `active_platform` xác định mà thiếu sub-key tương ứng → `active_service = unresolved`, ghi do để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
167
- - Entry là map-theo-prd_slug (2c) nhưng `prd_slug` xác định thiếu key tương ứng `active_service = unresolved`, ghi do rõ (không tự đoán submodule).
168
- - Entry sai cấu trúc (vừa có `path` vừa có `by_prd_slug`, hoặc `by_prd_slug` lồng nhau) → `active_service = unresolved`, nêu đúng key sai để người dùng sửa `project-context.yaml`.
164
+ **3. Fallback** — **hai trạng thái khác nhau, đừng gộp** *(G51)*:
165
+
166
+ > `unrouted` = **chưa ai quyết** repo. Hợp lệ, bình thường feature đầu tiên của domain mới.
167
+ > `unresolved` = **config sai cấu trúc**. **bug** cần sửa file, không phải trạng thái chờ.
168
+ >
169
+ > Trước G51 cả hai dùng chung tên `unresolved` nên chịu chung hình phạt: `/generate-bdd` DỪNG HẲN.
170
+ > Nhưng PRD/BDD là artifact **nghiệp vụ** — PO biết `domain` và biết `platform`, **không** biết code
171
+ > sẽ nằm repo nào, và thường lúc đó chưa ai quyết. Cổng đặt sai phase.
172
+
173
+ **→ `unrouted`** (chưa có mapping — **không** phải lỗi):
174
+ - Không phát hiện được domain, hoặc domain **không khớp key nào** trong `services` → giữ path mặc định từ Bước 1, đặt `active_service = unrouted`.
175
+ - Domain khớp map-theo-platform (2b) nhưng thiếu sub-key cho `active_platform` → `active_service = unrouted`, ghi lý do rõ (không tự đoán platform).
176
+ - Entry là map-theo-prd_slug (2c) nhưng thiếu key cho `prd_slug` → `active_service = unrouted`, ghi lý do rõ (không tự đoán submodule).
177
+
178
+ **→ `unresolved`** (config **sai cấu trúc** — bug):
179
+ - Entry vừa có `path` vừa có `by_prd_slug`, hoặc `by_prd_slug` lồng nhau → `active_service = unresolved`, nêu đúng key sai để người dùng sửa `project-context.yaml`.
180
+
181
+ *Cả hai đều KHÔNG chặn việc nạp context. Lệnh nào chặn là quyết định của lệnh đó: `/generate-bdd`
182
+ đi tiếp với `unrouted` (Step 1.6) · `/generate-code` DỪNG ở cả hai (nó buộc phải biết ghi vào đâu).*
169
183
 
170
184
  **4. Tự động override theo spec source** — nếu `setup.spec_source` được đặt VÀ path tương ứng chưa được set tường minh trong `paths:`:
171
185
  - Override `paths.specs_dir` → `{spec_source}/specs` — **luôn khi `spec_source` được đặt.** Mọi spec artifact (PRD, BDD, tech-docs, design-spec) nằm dưới gốc spec thống nhất trong spec repo dùng chung theo bố cục feature-package: `{spec_source}/specs/{domain}/{prd-slug}/`. Mọi umbrella (FE/App/BE) đều đọc từ đây. *(`specs/` theo service chỉ khi không có `spec_source`.)*
@@ -209,6 +223,13 @@ Khi `active_service` đã được phân giải thành một path thật ở Bư
209
223
 
210
224
  **4. Nếu không tìm thấy config của service** — giữ mặc định umbrella, vẫn set `service_root = {active_service}` (luôn cần mốc path kể cả khi không có config override).
211
225
 
226
+ > ⚠️ **`service_root` KHÔNG BAO GIỜ được là một chuỗi trạng thái** *(G51)*. Nếu `active_service` là
227
+ > `unrouted` / `unresolved` / `multi` / `—` thì đặt **`service_root = null`** và giữ path mặc định
228
+ > umbrella — **đừng** nội suy giá trị đó thành tên thư mục.
229
+ > Bản trước đặt `service_root = {active_service}` vô điều kiện, nên `/generate-code` (ghi file
230
+ > **tương đối với `service_root`**) sẽ ghi source vào một thư mục tên đúng chữ `unresolved/`.
231
+ > `service_root = null` là tín hiệu để `/generate-code` DỪNG thay vì ghi bừa.
232
+
212
233
  ---
213
234
 
214
235
  ## Bước 2 — [PROJECT-CONFIG] Nạp module stack profile (có điều kiện)
@@ -382,7 +403,7 @@ Dict : {loaded — N canonical terms, M banned terms | missing}
382
403
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
383
404
  Lessons : {loaded — {n} active cho lệnh này ({tổng} tổng) | chưa có}
384
405
  {⚠️ CHỈ IN khi tổng ≥ 40: "{tổng} guardrail đang hoạt động — /learn --review để rà"}
385
- Platform : {active_platform: system | web | app | — nếu chưa xác định}
406
+ Platform : {active_platform: system | web | app | webview | … | — nếu chưa xác định}
386
407
  Service : {active_service} ({active_service_module}) [← domain{/platform}{/prd_slug} nếu route qua by_prd_slug] | multi (map-theo-platform hoặc map-theo-prd_slug, chốt khi target đủ platform/prd_slug) | single-service
387
408
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
388
409
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
@@ -4,7 +4,7 @@
4
4
  # @trace.revision: 1 ← field tĩnh; version theo dõi bằng @trace.bdd_version
5
5
  # @trace.domain: <domain>
6
6
  # @trace.platform: {active_platform — web | app | system} ← BẮT BUỘC mọi mode; phải khớp segment bdd/{platform}/ của path
7
- # @trace.service: {active_service BẮT BUỘC mọi mode. "" single-service/spec repo mode; "multi" nếu chưa chốt; "unresolved" nếu routing sai. Nguồn của cột TSV `service` trace gộp không tách theo service nên đây là chỗ DUY NHẤT mang thông tin sở hữu}
7
+ # @trace.service: {service của ĐÚNG platform file nàyBẮT BUỘC mọi mode. Nguồn của cột TSV `service`; trace gộp không tách theo service nên đây là chỗ DUY NHẤT mang thông tin sở hữu ở cấp row. Bốn giá trị: {path} · "unrouted" (chưa ai quyết repo — HỢP LỆ, cờ 🟠, KHÔNG chặn) · "unresolved" (config sai cấu trúc — bug) · "—" (single-service). KHÔNG ghi "multi": file này đã có MỘT platform xác định nên service_candidates.{platform}.path đã biết — ghi path đó (G51)}
8
8
  # @trace.module: {active_module trong umbrella mode; "unknown" trong spec repo mode}
9
9
  # @trace.status: draft
10
10
  # @trace.author: AI-generated
@@ -26,7 +26,7 @@ project:
26
26
  paths:
27
27
  # Feature-Package Layout:
28
28
  # specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md — PRD document
29
- # specs/{domain}/{prd-slug}/bdd/{platform}/ — BDD .feature ({platform} = web | app | system)
29
+ # specs/{domain}/{prd-slug}/bdd/{platform}/ — BDD .feature ({platform} = web | app | system | webview)
30
30
  # specs/{domain}/{prd-slug}/tech-docs/ — Technical design (ONE merged doc per PRD: {TICKET-ID}-tech-design.md)
31
31
  # specs/{domain}/{prd-slug}/design-spec/ — Design specs (FE/App only)
32
32
  # specs/{domain}/{prd-slug}/changelog/ — PRD changelog overflow (created once history exceeds 5 versions)
@@ -97,7 +97,7 @@ paths:
97
97
  # {spec_source}/specs so FE/App read the contract via the spec submodule.
98
98
  tech_docs_dir: "specs"
99
99
 
100
- # Design Specs (FE/App platforms only — web, app).
100
+ # Design Specs (client platforms only — every platform except `system`: web, app, webview).
101
101
  # In the feature-package layout, design-specs live at specs/{domain}/{prd-slug}/design-spec/.
102
102
  # This variable is no longer needed as a separate path — derived from specs_dir.
103
103
  # design_spec_dir: "specs/design-spec" ← removed; use specs_dir instead
@@ -163,7 +163,7 @@ domains:
163
163
  # #
164
164
  # # FORM B — PER-PLATFORM MAP (one business-domain implemented on several platforms /
165
165
  # # submodules — a merged monorepo/workspace). No direct `path`; instead one
166
- # # sub-key per platform (system | web | app). context-loader routes by the
166
+ # # sub-key per platform (system | web | app | webview). context-loader routes by the
167
167
  # # target .feature's @trace.platform → picks {path, module} for that platform.
168
168
  # # The PRD keeps a SINGLE business @trace.domain (do NOT invent onboarding-web).
169
169
  # {{DOMAIN_2}}:
@@ -39,7 +39,7 @@
39
39
  @trace.ucs: {TICKET-ID}-UC1, {TICKET-ID}-UC2{, …}
40
40
  @trace.service: {service — từ header BDD @trace.service}
41
41
  @trace.module: {module liên quan — vd dotnet, angular}
42
- @trace.platforms: {system | web | app — tuỳ thư mục BDD nào tồn tại}
42
+ @trace.platforms: {system | web | app | webview | … — tuỳ thư mục BDD nào tồn tại}
43
43
  @trace.bdd_versions: {MAP theo từng platform — số nhiều, KHÁC @trace.bdd_version (scalar) của .feature — vd system=1.5, web=1.9, app=1.7; chỉ platform có mặt. Mỗi feature mang bdd_version riêng; đừng gộp về một số.}
44
44
  @trace.api_source: {existing | —}
45
45
  @trace.revision: 1
@@ -412,7 +412,7 @@ sequenceDiagram
412
412
 
413
413
  | UC | Feature | Platforms | Section phủ | Trạng thái |
414
414
  |----|---------|-----------|------------------|--------|
415
- | {TICKET-ID}-UC1 | {title} | {system, web, app} | §… | ✅ Covered |
415
+ | {TICKET-ID}-UC1 | {title} | {system, web, app, webview…} | §… | ✅ Covered |
416
416
 
417
417
  ### Độ phủ Scenario UC1
418
418
 
@@ -66,7 +66,7 @@ Spec-driven thành/bại phụ thuộc **~80%** vào việc context được n
66
66
  bin/self-check.js (fail build) --init cài vào đây
67
67
  ```
68
68
 
69
- **Vì sao slim (G45):** build inline `{{include:}}` vào **từng** file lệnh. Với 32 lệnh, kết quả là
69
+ **Vì sao slim (G45):** build inline `{{include:}}` vào **từng** file lệnh. Đo lúc đó (32 lệnh), kết quả là
70
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
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
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
@@ -86,6 +86,42 @@ Kết quả: `/generate-code` 108 KB → **69 KB**, `/refine-prd` 85 KB → **45
86
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
87
  > biến mất. Hai nhánh build gần giống nhau là nợ chờ lệch.
88
88
 
89
+ ### Tập publish — chỉ ship MỘT bản *(GAPS-v4 G59)*
90
+
91
+ `npm pack` chỉ mang **`bin/` · `core/` · `scripts/` · `docs/`**.
92
+
93
+ Trước G59, `files` có **10 mục**, và **7 trong 10** là bản sao của thứ đã có trong `core/` —
94
+ `commands/` (33/33 file `.md` **byte-identical** với `core/commands/`), cộng
95
+ `hooks/ modules/ rules/ skills/ steps/ templates/` (`diff -rq` không khác gì). Installer đọc
96
+ **chỉ `core/`** (`installCore(coreDir, agentDir, …)`), nên bản thứ hai không bao giờ được dùng.
97
+
98
+ | | Trước | Sau |
99
+ |---|---:|---:|
100
+ | Tarball nén | 1.2 MB | **710 kB** |
101
+ | Giải nén | 4.5 MB | **2.3 MB** |
102
+ | Số file | 395 | **215** |
103
+
104
+ **Nhưng cái đáng sửa hơn là một phép phân biệt bị vô hiệu.** `bin/index.js` dùng
105
+ `hasSources = exists(commands/generate-code.tmpl)` để biết *"đây là dev checkout hay bản cài từ
106
+ npm"*, và chú thích của nó viết thẳng: *"Chỉ nói trong DEV CHECKOUT. **Consumer không cần biết bước
107
+ này tồn tại**"*. Nhưng `commands/` được ship ⇒ `.tmpl` có mặt ⇒ phép thử **luôn đúng** ⇒ **mọi**
108
+ người dùng `npx` thấy `"Vừa sửa commands/*.tmpl ? Chạy npm run build trước"` — một câu họ không thể
109
+ làm gì với nó. *(Kiểm bằng cách `npm pack` rồi chạy tarball thật, không phải suy đoán.)*
110
+
111
+ Bốn nhánh sau khi sửa, `hasSources` đặt tên **một lần**:
112
+
113
+ | `corePrebuilt` | `hasSources` | Nghĩa | Làm gì |
114
+ |:---:|:---:|---|---|
115
+ | ✗ | ✓ | dev checkout, `core/` vắng/lệch | build từ nguồn |
116
+ | ✗ | ✗ | **bản cài npm bị thiếu/hỏng** | **lỗi rõ ràng + `exit 1`** — không cố build (G43: build ghi vào npx cache / global `node_modules`, có thể read-only, và hai `--init` song song sẽ đua nhau) |
117
+ | ✓ | ✓ | dev checkout, đã khớp version | in lời nhắc *"sửa `.tmpl` thì build lại"* |
118
+ | ✓ | ✗ | **bản cài npm, mọi thứ đúng** | **im lặng** ← đường của consumer |
119
+
120
+ Bất biến được `test/run.js` canh, viết theo **hình dạng** chứ không theo danh sách tên nên tự khớp
121
+ với dir thêm sau này: *không mục nào trong `files` được có bản mirror dưới `core/`*.
122
+
123
+ `scripts/` **phải giữ** — `bin/index.js` `require('../scripts/migrate-specs.js')` cho `--migrate-*`.
124
+
89
125
  - Cơ chế `{{include:steps/...}}` → single source of truth ở `.tmpl` + `steps/`.
90
126
  - **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
127
  - **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`.
@@ -11,7 +11,7 @@
11
11
  ```mermaid
12
12
  flowchart TD
13
13
  S["0 · Setup<br/>/setup-ai-first"] --> D["1 · Discovery<br/>/define-product"]
14
- D --> SP["2 · Specification<br/>/generate-prd · /refine-prd · /review-context"]
14
+ D --> SP["2 · Specification<br/>/generate-prd · /extend-prd · /amend-prd<br/>/refine-prd · /review-context"]
15
15
  SP --> DS["3 · Design-Spec<br/>(chỉ FE/App)"]
16
16
  SP --> B["4 · BDD<br/>/generate-bdd · /review-context"]
17
17
  DS --> B
@@ -3,15 +3,20 @@
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` (lần đầu) · `/extend-prd` (thêm vào PRD đã có) → `/refine-prd` → `/review-context`
6
+ > **Commands:** `/generate-prd` (lần đầu) · `/extend-prd` (**thêm** vào PRD đã có) · `/amend-prd` (**đổi** yêu cầu đã có) → `/refine-prd` → `/review-context`
7
7
 
8
- > **Chọn lệnh nào — PRD mới vs PRD đã có:**
8
+ > **Chọn lệnh nào — bốn nhánh, phân biệt bằng THAO TÁC GHI:**
9
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 tự cấm đụng section ngoài findings |
10
+ > | Tình huống | Lệnh | Ghi kiểu gì | Vì sao không dùng cái kia |
11
+ > |---|---|---|---|
12
+ > | PRD **chưa tồn tại** | `/generate-prd` | **Write** cả file | — |
13
+ > | PRD đã có, **THÊM** UC/AC/BR mới | **`/extend-prd`** | Edit **add-only** — output là **superset chặt** | `/generate-prd` **từ chối chạy** trên file đã có |
14
+ > | PRD đã có, **ĐỔI** một yêu cầu đang đúng cú pháp | **`/amend-prd`** | Edit **tại chỗ** output **KHÔNG** phải superset | `/extend-prd` chỉ add-only; `/refine-prd` chỉ áp finding của chính nó |
15
+ > | PRD đã có, sửa **vấn đề review đã soi ra** | `/refine-prd` → Review Board → `--resume` | Edit trong phạm vi finding | `/refine-prd` **không thêm/đổi được** theo ý định mới — nó tự cấm đụng section ngoài findings |
16
+ >
17
+ > **Xoá hẳn một BR/AC → không có lệnh, và có chủ ý:** xoá row làm `@trace.business_rules` trong `.feature` trỏ vào ID không còn ⇒ `TRACE_ORPHAN` 🔴. Dùng `/amend-prd --retire {ID}` — khai tử **tại chỗ**, giữ nguyên row + ID.
18
+ >
19
+ > ⚠️ **Sửa tay file `.md` là điểm mù (GAPS-v4 G54).** Mọi drift detector so **nhãn version**, không so nội dung (0 content hash trong codebase) — sửa mà không bump version ⇒ **0 cờ**. `/validate-traces` Step 3.9 canh cửa sau bằng cờ 🔴 `PRD_UNTRACKED_EDIT`.
15
20
  >
16
21
  > **`/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.
17
22
 
@@ -41,6 +46,7 @@ PRD là **hợp đồng nghiệp vụ** giữa PO ↔ Dev ↔ AI. Đây là **c
41
46
  |------|---------|---------|
42
47
  | `/generate-prd` | **Sinh** PRD draft từ product-definition. Từ chối chạy nếu PRD đã tồn tại | PRD `Status: draft` |
43
48
  | `/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` |
49
+ | `/amend-prd` | **Đổi tại chỗ** một AC/BR/UC đã duyệt — PO khai tường minh `amend_targets`, kiểm va chạm, guard sau-ghi **HAI CHIỀU** (Bảo toàn + Giới hạn). `--retire {ID}` khai tử tại chỗ | PRD v+1, `Status → draft` |
44
50
  | `/refine-prd` | **Tinh chỉnh** qua 3 lăng kính DEV/SA/PO (fan-out per-UC) | Findings để PO accept/reject |
45
51
  | `/review-context` | **Gate chất lượng** — findings P0–P5, phải sạch critical | PO đặt `Status: approved` |
46
52
 
@@ -24,6 +24,8 @@ Trước khi đẩy sang QC chính thức, Dev cần một vòng **kiểm nhanh
24
24
  - Cho phép **thử tại chỗ** trên service/app đang chạy (`/dev-smoke-test`).
25
25
 
26
26
  > **`dev_selftest` ≠ `qc_status`.** Hai trục **độc lập**: dev smoke (nhanh, tự kiểm) vs QC chính thức (Playwright, evidence). Không lấn quyền nhau.
27
+ >
28
+ > ⚠️ **Nhưng "độc lập" chỉ đúng với `status` về KẾT QUẢ CHẠY, không đúng về QUYỀN KHẲNG ĐỊNH** *(GAPS-v4 G55)*. `pass` mang nghĩa *"scenario này đã được nghiệm thu theo spec **hiện tại**"* — nên trên row `DRIFT`/`ORPHANED`, `/dev-run-test` và `/qc-run-test` **không được** ghi `pass`; chúng hạ về `not_run`. `fail`/`skip` thì ghi bình thường. `lint-trace` **T12** bắt trạng thái `DRIFT + pass` ở sổ thật, bất kể ai ghi ra.
27
29
 
28
30
  ---
29
31
 
@@ -21,6 +21,7 @@
21
21
 
22
22
  - Phân rã yêu cầu thành test case bám scenario, phát hiện **gap tài liệu**.
23
23
  - Chạy test thật, ghi **`qc_status` chính thức** + **evidence**.
24
+ ⚠️ Nhưng `/qc-run-test` **đọc cột `status` trước khi ghi `pass`** *(GAPS-v4 G55)*: row `DRIFT`/`ORPHANED` + test xanh → hạ về `not_run`, và **không** đóng bug nào ở lần chạy đó. `fail`/`skip` ghi bình thường.
24
25
  - Phân loại FAIL: **script-bug** (sửa script) vs **product-gap** (giữ FAIL + evidence, **không bao giờ fake-pass**).
25
26
  - Đẩy **product-gap** ngược về PO/Dev.
26
27
 
@@ -2,7 +2,8 @@
2
2
 
3
3
  # Bước 9 · Validate Traces — Ma trận độ phủ (Coverage Matrix)
4
4
 
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ì**.
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, 1 cờ 🔴 không-chặn (`PRD_UNTRACKED_EDIT`), 2 cờ ⓘ. Chỉ ra chỗ chưa phủ — mặc định **không sửa gì**.
6
+ > **Có phạm vi:** `--domain {d}` · `--prd {TICKET-ID}` · `--uc {UC-ID}`; không cờ nào = toàn bộ.
6
7
  > **Command:** `/validate-traces` · `--realign-prd-version {UC-ID}` · `--realign-techdoc-revision {UC-ID}`
7
8
  >
8
9
  > *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ờ-ⓘ).*
@@ -41,7 +42,7 @@ Traceability chỉ có giá trị khi **kiểm được**. Bước này cho mộ
41
42
  | Ma trận coverage spec ↔ code ↔ test | Trạng thái từng SC + `code_coverage` tổng |
42
43
  | `{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
44
  | `{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
+ | Cờ audit | 6 cờ drift + 4 cờ 🔴 chặn PR + `PRD_UNTRACKED_EDIT` 🔴 (không chặn) + 2 cờ ⓘ (bảng dưới) |
45
46
  | Hàng đợi | Đếm PRD change request còn `Open` kèm **số ngày chờ** (Step 7b) |
46
47
 
47
48
  ---
@@ -68,6 +69,25 @@ Traceability chỉ có giá trị khi **kiểm được**. Bước này cho mộ
68
69
 
69
70
  ## Framework xử lý thế nào (Mechanics)
70
71
 
72
+ ### Phạm vi audit — `--domain` / `--prd` / `--uc`
73
+
74
+ Đây là **lệnh đắt nhất** trong framework: ~24k token chỉ dẫn + ~9k `context-loader`, rồi đọc **mọi** PRD · `.feature` · tech-doc · design-spec · file source có tag · `.tsv`. Chi phí tăng **tuyến tính theo cả repo**, không theo phần việc đang làm.
75
+
76
+ | Cờ | `scope.kind` | Phạm vi |
77
+ |---|---|---|
78
+ | *(không có)* | `all` | Toàn bộ |
79
+ | `--domain {d}` | `domain` | Một domain |
80
+ | `--prd {TICKET-ID}` | `prd` | Một feature-package |
81
+ | `--uc {UC-ID}` | `uc` | Một UC — **mọi platform của nó** |
82
+
83
+ **`/sync` Step 1e nói cho bạn biết scope là gì**: nó liệt kê PRD nào vừa đổi *(so với lần pull)* và PRD nào đã đổi *kể từ lần audit gần nhất* — con số thứ hai tích luỹ đúng qua nhiều lần pull. Hai lệnh khớp nhau thành một vòng: `/sync` chỉ chỗ → audit scoped rẻ → sửa → audit **toàn bộ** một lần trước khi tạo PR.
84
+
85
+ ⚠️ **Biên bản có scope KHÔNG BAO GIỜ được coi là đầy đủ.** Report mang field `scope`, và `gate-trace` **G2 fail** nếu `scope.kind !== "all"` — **không ngoại lệ**, không đếm xem trên đĩa có bao nhiêu domain. Muốn tạo PR thì phải có một lần audit **toàn bộ** đã commit.
86
+
87
+ > **Vì sao điều kiện phải tuyệt đối (GAPS-v4 G57):** bản cũ hỏi *"còn domain **nào khác** không"*, nên trong repo **một domain** thì không còn domain nào khác ⇒ **không fail** ⇒ một biên bản hẹp-theo-PRD được nhận là *"toàn bộ"*. Thêm cờ scope mà không siết G2 là **tự tay mở** đúng cái *"cấp giấy xanh cho thứ chưa ai xem"* mà chú thích của gate cảnh báo.
88
+
89
+ **Ba chỗ cố ý KHÔNG âm thầm:** `--prd`/`--uc` không phân giải được → **DỪNG** *(không rơi về `all` — chạy toàn bộ khi người ta xin một phần là đốt 30 phút; và không audit rỗng rồi báo "sạch" trên 0 row)* · nhiều cờ scope cùng lúc → **DỪNG** *(không tự ưu tiên)* · **lint vẫn chạy toàn bộ** dù audit có scope *(sổ hỏng ở domain khác vẫn là sổ hỏng, và lint rẻ vì không cần LLM)*.
90
+
71
91
  ### Phân loại `status` từng SC (thứ tự ưu tiên, rule sớm thắng)
72
92
 
73
93
  | # | Trạng thái | Điều kiện |
@@ -97,6 +117,7 @@ Chiều ngược là cần thiết vì gen lại BDD có thể làm một SC bi
97
117
 
98
118
  | Cờ | So cái gì | Step |
99
119
  |---|---|:---:|
120
+ | `PRD_UNTRACKED_EDIT` 🔴 | **Nội dung PRD đổi mà nhãn `Version` KHÔNG đổi** — `git diff` **và** `git status` so với mốc `spec_baseline` của lần audit trước. Có người sửa ngoài đường chính thức | **3.9** |
100
121
  | `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
122
  | `TECHDOC_DRIFT` · `FE_TECHDOC_DRIFT` | `@trace.revision` tech-doc vs cột đã lưu — **và** changelog nêu UC này | 5 |
102
123
  | `BDD_DRIFT` | `@trace.bdd_version` trong code vs `.feature` hiện tại | 5c |
@@ -133,7 +154,17 @@ Chiều ngược là cần thiết vì gen lại BDD có thể làm một SC bi
133
154
 
134
155
  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
156
 
136
- Bộ lọc đọc **scope của row changelog** (`/refine-prd` Phase 3 `/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*.
157
+ Bộ lọc đọc **`{changelog_scope}` của row changelog** — một **contract máy đọc** (`bin/trace-schema.json` → `changelog_row_contract`) với **bốn** producer: `/refine-prd` Phase 3 · `/extend-prd` Bước 6 · `/amend-prd` Bước 5 · `/review-context` Fix/Resume Phase 3. `self-check` **R12** fail build nếu producer nào không dòng template mang token.
158
+
159
+ Ba bước dựng tập bị ảnh hưởng:
160
+
161
+ 1. **Tách mệnh đề** — ngăn bằng `;`, mỗi mệnh đề mở đầu bằng đơn vị sở hữu (`{UC-ID}:` hoặc `PRD-global:`).
162
+ 2. **Chuẩn hoá về UC** — phép phân giải **`BR/AC → UC sở hữu`**: `BR{n}` → UC có BR đó trong bảng Business Rule (PRD §3) · `AC{n}` → UC có AC đó ở dòng `**AC liên quan:**`. **Không bỏ bước này**: phép thử là *"**UC** này có trong tập?"*, nên một row chỉ nêu `sửa BR8` làm UC sở hữu BR8 rơi vào ⓘ trong khi nội dung của nó vừa đổi — và ⓘ **mở cửa** cho `--realign-prd-version` dán nhãn lại (GAPS-v4 G53).
163
+ 3. **Phân loại** *(first-match-wins)* — **row mơ hồ xét TRƯỚC**: nó là điều kiện **cấp row**, nên xét sau thì một UC có thể được xếp ⓘ trước khi ta biết là không suy đoán được gì.
164
+
165
+ **Row nào mơ hồ → 🟠 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*. ⚠️ Nhưng nó **không phải cái cớ để producer ghi bừa**: đúng khi **thiếu** thông tin, sai khi producer **có** thông tin mà không ghi.
166
+
167
+ Mệnh đề mang hậu tố **`[no-behavior]`** → UC nêu trong đó ở lại ⓘ. Chỉ producer **chứng minh được** tính trung tính mới được dùng (`changelog_row_contract.neutral_checks`) — hiện chỉ `/review-context --fix` cho fix thuần cấu trúc (P4).
137
168
 
138
169
  > Đâ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
170
 
@@ -37,7 +37,7 @@ Framework là pipeline **một chiều** — nhưng vẫn cần đường **ph
37
37
  | `/learn` | Tất cả | Guardrail lesson | `project-lessons.md` (qua step `capture-lesson`) |
38
38
  | `/fix-bug` | Dev | Sửa lỗi có root-cause + regression test | Code + `@trace.fixes/root_cause/regression` |
39
39
  | `/extend-prd` | PO | **Drain** PRD change request → UC/AC/BR mới trong PRD | PRD v+1 · request → `archived/` |
40
- | `/sync` | Lead (umbrella) | Pull + submodule + **nổi feedback** + làm mới Living Docs | Chạy hằng ngày |
40
+ | `/sync` | Lead (umbrella) | Pull + submodule + **nổi feedback** + **nổi spec delta** (Step 1e) + làm mới Living Docs | Chạy hằng ngày |
41
41
 
42
42
  ### Ba hàng đợi — mỗi cái phải có người lấy ra
43
43
 
@@ -48,6 +48,15 @@ Framework là pipeline **một chiều** — nhưng vẫn cần đường **ph
48
48
  | `prd-change-requests/` | `/propose-scenario` B | **`/extend-prd`** | `/validate-traces` Step 7b — đếm `Status: Open` kèm **số ngày chờ** |
49
49
 
50
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
+ > **Cùng nguyên tắc đó áp cho SPEC — và đó là Step 1e (GAPS-v4 G56).** Trước đó `/sync` diff đúng ba đường dẫn `feedback/*` và **bỏ qua `specs/`**, tức hỏi *"có góp ý gì mới"* rồi bỏ qua chính tài liệu mà mọi lệnh downstream đọc. Giờ nó trả lời **hai** câu bằng **hai** mốc:
53
+ >
54
+ > | | Mốc | Trả lời | Vấn đề nếu chỉ có nó |
55
+ > |---|---|---|---|
56
+ > | **1e-A** | `{old_sha}..{new_sha}` | *"đổi gì kể từ lần **PULL**"* | **chuông cửa** — reset mỗi lần pull; pull 4 ngày liền không audit thì ngày thứ 5 chỉ thấy delta của **một** ngày |
57
+ > | **1e-B** | `spec_baseline.sha_at_audit` | *"đổi gì kể từ lần **AUDIT**"* | **tồn kho** — tích luỹ đúng |
58
+ >
59
+ > 1e-B đọc mốc mà `/validate-traces` Step 6b ghi (cùng khối dùng cho cờ `PRD_UNTRACKED_EDIT`). `/sync` **chỉ đọc, không bao giờ ghi** — nếu nó cũng ghi thì mốc audit trượt theo mỗi lần pull, tức 1e-B thoái hoá thành 1e-A. Và dòng `Next` giờ **rẽ nhánh theo dữ liệu**, không còn in một hằng số.
51
60
  >
52
61
  > 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
62