@educa-corp/sdd-framework 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/bin/build.js +113 -19
  2. package/bin/gate-trace.js +464 -0
  3. package/bin/index.js +418 -146
  4. package/bin/lint-trace.js +602 -0
  5. package/bin/self-check.js +499 -6
  6. package/bin/trace-schema.json +1449 -692
  7. package/commands/debug.md +123 -510
  8. package/commands/debug.tmpl +3 -0
  9. package/commands/define-product.md +86 -509
  10. package/commands/dev-gen-test.md +120 -516
  11. package/commands/dev-run-test.md +120 -516
  12. package/commands/dev-smoke-test.md +86 -509
  13. package/commands/extend-prd.md +486 -0
  14. package/commands/extend-prd.tmpl +273 -0
  15. package/commands/fix-bug.md +152 -515
  16. package/commands/generate-architecture.md +94 -514
  17. package/commands/generate-architecture.tmpl +3 -0
  18. package/commands/generate-bdd.md +138 -519
  19. package/commands/generate-bdd.tmpl +18 -3
  20. package/commands/generate-code.md +156 -523
  21. package/commands/generate-code.tmpl +36 -7
  22. package/commands/generate-design-spec.md +86 -509
  23. package/commands/generate-prd.md +114 -509
  24. package/commands/generate-prd.tmpl +28 -0
  25. package/commands/generate-spec-manifest.md +86 -509
  26. package/commands/generate-tech-docs.md +86 -509
  27. package/commands/learn.md +172 -495
  28. package/commands/learn.tmpl +70 -3
  29. package/commands/map-testids.md +86 -509
  30. package/commands/propose-scenario.md +136 -508
  31. package/commands/propose-scenario.tmpl +52 -1
  32. package/commands/qc-analyze.md +86 -509
  33. package/commands/qc-design-test.md +87 -509
  34. package/commands/qc-design-test.tmpl +1 -0
  35. package/commands/qc-plan.md +86 -509
  36. package/commands/qc-report.md +86 -509
  37. package/commands/qc-review.md +86 -509
  38. package/commands/qc-run-test.md +133 -517
  39. package/commands/qc-run-test.tmpl +13 -1
  40. package/commands/refine-prd.md +99 -519
  41. package/commands/refine-prd.tmpl +3 -0
  42. package/commands/report-bug.md +86 -509
  43. package/commands/review-code.md +127 -513
  44. package/commands/review-code.tmpl +7 -3
  45. package/commands/review-context.md +96 -515
  46. package/commands/review-context.tmpl +6 -2
  47. package/commands/review-tech-docs.md +90 -510
  48. package/commands/review-tech-docs.tmpl +3 -0
  49. package/commands/setup-ai-first.md +166 -137
  50. package/commands/setup-ai-first.tmpl +72 -0
  51. package/commands/sync.md +86 -118
  52. package/commands/sync.tmpl +84 -16
  53. package/commands/update-framework.md +16 -102
  54. package/commands/update-framework.tmpl +14 -0
  55. package/commands/validate-traces.md +458 -531
  56. package/commands/validate-traces.tmpl +381 -31
  57. package/core/FRAMEWORK_VERSION +1 -1
  58. package/core/README.md +20 -0
  59. package/core/commands/debug.md +123 -510
  60. package/core/commands/define-product.md +86 -509
  61. package/core/commands/dev-gen-test.md +120 -516
  62. package/core/commands/dev-run-test.md +120 -516
  63. package/core/commands/dev-smoke-test.md +86 -509
  64. package/core/commands/extend-prd.md +486 -0
  65. package/core/commands/fix-bug.md +152 -515
  66. package/core/commands/generate-architecture.md +94 -514
  67. package/core/commands/generate-bdd.md +138 -519
  68. package/core/commands/generate-code.md +156 -523
  69. package/core/commands/generate-design-spec.md +86 -509
  70. package/core/commands/generate-prd.md +114 -509
  71. package/core/commands/generate-spec-manifest.md +86 -509
  72. package/core/commands/generate-tech-docs.md +86 -509
  73. package/core/commands/learn.md +172 -495
  74. package/core/commands/map-testids.md +86 -509
  75. package/core/commands/propose-scenario.md +136 -508
  76. package/core/commands/qc-analyze.md +86 -509
  77. package/core/commands/qc-design-test.md +87 -509
  78. package/core/commands/qc-plan.md +86 -509
  79. package/core/commands/qc-report.md +86 -509
  80. package/core/commands/qc-review.md +86 -509
  81. package/core/commands/qc-run-test.md +133 -517
  82. package/core/commands/refine-prd.md +99 -519
  83. package/core/commands/report-bug.md +86 -509
  84. package/core/commands/review-code.md +127 -513
  85. package/core/commands/review-context.md +96 -515
  86. package/core/commands/review-tech-docs.md +90 -510
  87. package/core/commands/setup-ai-first.md +166 -137
  88. package/core/commands/sync.md +86 -118
  89. package/core/commands/update-framework.md +16 -102
  90. package/core/commands/validate-traces.md +458 -531
  91. package/core/hooks/data-guard.js +174 -83
  92. package/core/hooks/settings.json +2 -1
  93. package/core/rules/workflow.md +48 -4
  94. package/core/steps/capture-lesson.md +34 -1
  95. package/core/steps/context-loader.md +24 -3
  96. package/core/steps/gate.md +92 -35
  97. package/core/steps/report-footer.md +26 -2
  98. package/core/steps/trace-mirror.md +34 -7
  99. package/core/templates/README.md +24 -1
  100. package/core/templates/ci/trace-gate.yml +146 -0
  101. package/core/templates/feature.template +1 -1
  102. package/core/templates/hooks/pre-push +61 -0
  103. package/docs/01-getting-started/installation.md +18 -1
  104. package/docs/01-getting-started/what-is-sdd.md +4 -2
  105. package/docs/02-concepts/architecture.md +48 -5
  106. package/docs/02-concepts/pipeline-steps/02-specification.md +39 -3
  107. package/docs/02-concepts/pipeline-steps/04-bdd.md +24 -2
  108. package/docs/02-concepts/pipeline-steps/05-tech-docs.md +18 -1
  109. package/docs/02-concepts/pipeline-steps/06-code.md +35 -4
  110. package/docs/02-concepts/pipeline-steps/09-validate-traces.md +137 -12
  111. package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +59 -3
  112. package/docs/02-concepts/roles-and-hitl.md +1 -1
  113. package/docs/02-concepts/traceability.md +183 -117
  114. package/docs/03-guides/architect.md +63 -0
  115. package/docs/03-guides/developer.md +20 -4
  116. package/docs/03-guides/product-owner.md +72 -68
  117. package/docs/03-guides/tester-qa.md +81 -70
  118. package/docs/04-reference/commands.md +134 -105
  119. package/docs/04-reference/configuration.md +146 -94
  120. package/docs/04-reference/model-selection.md +32 -19
  121. package/docs/04-reference/trace-schema.md +26 -9
  122. package/docs/explain/02-generate-prd.md +80 -78
  123. package/docs/explain/02b-extend-prd.md +125 -0
  124. package/docs/explain/03-refine-prd.md +86 -86
  125. package/docs/explain/04-review-context.md +18 -1
  126. package/docs/explain/06-generate-bdd.md +23 -0
  127. package/docs/explain/08-review-tech-docs.md +20 -5
  128. package/docs/explain/10-review-code.md +36 -2
  129. package/docs/explain/19-qc-run-test.md +87 -67
  130. package/docs/explain/21-validate-traces.md +75 -68
  131. package/docs/explain/23-fix-bug.md +19 -3
  132. package/docs/explain/26-propose-scenario.md +70 -63
  133. package/docs/explain/27-learn.md +5 -3
  134. package/docs/explain/README.md +135 -134
  135. package/hooks/data-guard.js +174 -83
  136. package/hooks/settings.json +2 -1
  137. package/package.json +53 -50
  138. package/rules/workflow.md +48 -4
  139. package/steps/capture-lesson.md +34 -1
  140. package/steps/context-loader.md +24 -3
  141. package/steps/gate.md +92 -35
  142. package/steps/report-footer.md +26 -2
  143. package/steps/trace-mirror.md +34 -7
  144. package/templates/README.md +24 -1
  145. package/templates/ci/trace-gate.yml +146 -0
  146. package/templates/feature.template +1 -1
  147. package/templates/hooks/pre-push +61 -0
  148. package/scripts/init.sh +0 -49
  149. package/scripts/upgrade.sh +0 -94
@@ -17,35 +17,31 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
17
17
  - Đi thẳng tới phần logic riêng của lệnh.
18
18
  3. Nếu `$ARGUMENTS` không phải JSON hoặc không có `_agent_mode` → tiếp tục sang Bước 1 (chế độ thường).
19
19
 
20
- ## Bước 0-B — Kiểm tra Model
20
+ ## Bước 0-B — Ghi nhận Model *(KHÔNG chặn)*
21
21
 
22
- *Bỏ qua bước này nếu `_agent_mode: true` (sub-agent — orchestrator đã kiểm tra rồi).*
22
+ *Bỏ qua nếu `_agent_mode: true` (sub-agent — orchestrator đã ghi nhận rồi).*
23
23
 
24
- Các lệnh sinh nội dung review phức tạp đòi hỏi khả năng suy luận mạnh.
25
- Dùng model nhỏ hơn sẽ rủi ro: bỏ sót edge case, phân tích spec thiếu sót, vi phạm kiến trúc.
24
+ Ghi lại **model bạn agent đang chạy lệnh này thực sự đang dùng**, rồi mang nó vào
25
+ dòng `Model:` của report cuối (xem `report-footer`). Nếu bạn biết mình **không** phải một
26
+ model Opus, gắn thêm cảnh báo ngay ở dòng đó.
26
27
 
27
- Hiển thị chờ phản hồi:
28
+ **KHÔNG hỏi người dùng. KHÔNG chờ. KHÔNG dừng.**
28
29
 
29
- ```
30
- ⚙️ MODEL CHECK
31
- ──────────────────────────────────────────────────────────────────
32
- Recommended : model Opus mới nhất
33
- Why needed : Phân tích spec, review kiến trúc, sinh code đòi hỏi
34
- suy luận sâu. Model nhỏ hơn (Haiku/Sonnet) dễ bỏ sót edge case.
35
-
36
- Cách đổi trong Claude Code:
37
- /model chọn model Opus
38
- • hoặc: Settings → Model
39
-
40
- Đang chạy một model Opus?
41
- Y — đúng → tiếp tục
42
- S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
43
- ──────────────────────────────────────────────────────────────────
44
- ```
30
+ > **Vì sao bước này từng là prompt chặn, và vì sao bỏ (GAPS-v3 G41):** bản cũ hiện khối
31
+ > `⚙️ MODEL CHECK` rồi chờ `Y/S/N`. Ba vấn đề cùng chỉ một hướng:
32
+ > **(1)** nó hỏi người dùng thứ mà **agent đã biết chính xác**;
33
+ > **(2)** câu trả lời **không kiểm chứng được** — gõ `Y` xong vẫn đang chạy Haiku thì không
34
+ > phát hiện;
35
+ > **(3)** **cả `Y` lẫn `S` đều đi tiếp** cách duy nhất để nó dừng là tự nguyện gõ `N`.
36
+ > Tức nó **không chặn được ai**, mà tốn một lần chặn ở **mọi** lệnh. Một feature đi hết
37
+ > pipeline dùng 20 lệnh; 30/32 lệnh chạy gate. Hai mươi lần bấm cho một tín hiệu tự-khai
38
+ > không kiểm chứng được — và chính cái giá đó làm mòn CHECKPOINT ở Bước 3, cổng có giá trị thật.
39
+ >
40
+ > Khai báo trong report **mạnh hơn** hỏi: đúng nguồn (agent, không phải người), và nằm
41
+ > **cạnh kết quả** để cân nhắc, thay vì nằm trước khi có kết quả để bấm cho xong.
45
42
 
46
- - "Y" tiếp tục sang Bước 1.
47
- - "S" tiếp tục sang Bước 1 (người dùng chấp nhận rủi ro, thêm ⚠️ vào report cuối).
48
- - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang một model Opus (`/model`) rồi chạy lại lệnh này."
43
+ **Vẫn khuyến nghị Opus:** phân tích spec, review kiến trúc và sinh code đòi hỏi suy luận sâu;
44
+ model nhỏ hơn dễ bỏ sót edge case vi phạm kiến trúc. Đổi: `/model` chọn Opus.
49
45
 
50
46
  ## Bước 1 — Xác định Target File
51
47
 
@@ -75,20 +71,81 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
75
71
 
76
72
  ## Bước 3 — CHECKPOINT
77
73
 
78
- Sau khi hoàn thành Bước 1 và 2, hiển thị bản tóm tắt và chờ xác nhận:
74
+ *Bỏ qua nếu `_agent_mode: true`.*
75
+
76
+ ### 3a — Lệnh này có phải chặn không?
77
+
78
+ | Mức | Lệnh nào | `--yes` bỏ qua được? |
79
+ |---|---|:---:|
80
+ | **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
81
+ | **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
82
+ | **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
83
+
84
+ `--yes` trong `$ARGUMENTS` → bỏ qua CHECKPOINT mức *chặn thường*. (Bước 1 đã tách mọi token
85
+ `--` khỏi phần resolve target, nên cờ này không ảnh hưởng việc tìm file.) Mở đường chạy
86
+ headless: `claude -p "/generate-code UC1 --yes"`.
87
+
88
+ > **KHÔNG tự suy mức từ bảng này.** Mỗi lệnh **tự khai** mức của nó ở một dòng `*Checkpoint: …*`
89
+ > ngay dưới `## Gate` của chính nó — đọc dòng đó, đừng suy diễn. Bảng trên chỉ giải thích ba mức
90
+ > **nghĩa là gì**.
91
+ > Nguồn máy đọc: `bin/trace-schema.json` → `gate.checkpoint_levels`; `self-check` **R11** fail
92
+ > build nếu nhãn trong file lệnh lệch với schema, hoặc nếu một lệnh `hard`/`none` thiếu nhãn.
93
+ > *(Lệnh không có dòng nào = mức **chặn thường**, mặc định.)*
94
+
95
+ > **Mức *không chặn* là thực thi đúng miễn trừ mà `rules/workflow.md` đã cấp từ trước** —
96
+ > trước G41 file đó viết *"read-only commands may skip CHECKPOINT"* còn gate thì luôn đòi.
97
+ > Hai file cùng được nạp vào mọi lệnh mà nói ngược nhau; agent theo cái nào là tuỳ lúc.
98
+
99
+ ### 3b — In gì
100
+
101
+ **KHÔNG lặp lại những gì `[CTX LOADED]` vừa in.** Recap của context-loader (Bước 7) đã hiện
102
+ Stack · Platform · Layers · CLAUDE.md · Dict · Entities · Lessons · Service · Status ngay phía
103
+ trên. CHECKPOINT chỉ thêm **một** thông tin mới là `Target`.
104
+
105
+ **Mọi thứ sạch** — recap báo `Status: FULL`, không cờ nào bật → in đúng hai dòng:
79
106
 
80
107
  ```
81
- CHECKPOINT
82
- -----------
83
- Target : {resolved file path}
84
- Project : {project.name từ project-context.yaml}
85
- Tech stack : {language} / {framework}
86
- Module : {module nếu có, else "not configured"}
87
- Domains : {danh sách domain, ngăn cách bởi dấu phẩy}
108
+ CHECKPOINT — Target: {resolved file path}
109
+ Tiếp tục? (Y/N)
110
+ ```
111
+
112
+ **Có bất thường** thêm một dòng cho **mỗi** trạng thái, nặng nhất lên đầu:
88
113
 
114
+ ```
115
+ CHECKPOINT
116
+ 🔴 Service : unresolved — {lý do context-loader đã ghi}
117
+ ⚠️ CLAUDE.md: service overlay THIẾU — dùng root (code sinh ra có thể sai stack)
118
+ ⚠️ Target : resolve bằng wildcard — {n} file khớp, chọn {file}
119
+ ⚠️ Module : not configured — code sinh ra sẽ dùng default
120
+ Status : PARTIAL — thiếu: {danh sách}
121
+ Target : {resolved file path}
89
122
  Tiếp tục? (Y/N)
90
123
  ```
91
124
 
92
- Chờ người dùng trả lời ràng "Y" hoặc "N" rồi mới tiếp tục.
93
- - "Y" → tiếp tục sang các bước riêng của lệnh bên dưới.
94
- - "N" dừng lại hỏi người dùng muốn thay đổi gì.
125
+ ### 3c Cờ nào bật, cờ nào KHÔNG
126
+
127
+ Mỗi dòng ⚠️/🔴 phải ứng với một trạng thái **context-loader đã tính rồi** — không phát minh
128
+ điều kiện mới, chỉ mang thứ đang bị giấu lên chỗ người dùng phải quyết định:
129
+
130
+ | Bật cờ khi | Nguồn | Mức |
131
+ |---|---|:---:|
132
+ | `active_service = unresolved` | context-loader Bước 2b/2c/Fallback | 🔴 |
133
+ | `Status = MINIMAL` | recap Bước 7 | 🔴 |
134
+ | `Status = PARTIAL` | recap Bước 7 | ⚠️ |
135
+ | CLAUDE.md thiếu, hoặc service overlay thiếu | context-loader Bước 3 | ⚠️ |
136
+ | Target resolve qua wildcard, hoặc nhiều file khớp mà lệnh tự chọn | Bước 1 ở trên | ⚠️ |
137
+ | `module` không cấu hình | recap Bước 7 | ⚠️ |
138
+
139
+ **KHÔNG bật cờ cho:** `Lessons: chưa có` · `Dict: missing` · `Entities: missing`. Đó là
140
+ *"dự án chưa điền"*, không phải *"có gì đó sai"* — chúng ở lại trong recap.
141
+
142
+ > **Nguyên tắc một câu:** cờ dành cho thứ **framework không chắc chắn hoặc đã phải đoán**,
143
+ > không dành cho thứ **người dùng chưa làm**. Đẩy hết mọi thứ lên thì CHECKPOINT lại đầy như
144
+ > cũ, và ta quay về đúng chỗ xuất phát: một cổng luôn giống nhau thì bị lướt qua.
145
+
146
+ ### 3d — Chờ trả lời
147
+
148
+ - "Y" → tiếp tục sang các bước riêng của lệnh.
149
+ - "N" → dừng, hỏi người dùng muốn thay đổi gì.
150
+ - Có `--yes` và mức *chặn thường* → coi như "Y", **nhưng vẫn IN khối CHECKPOINT** nếu có cờ
151
+ 🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
@@ -2,6 +2,29 @@
2
2
 
3
3
  Mọi report của lệnh phải kết thúc bằng section footer chuẩn này.
4
4
 
5
+ ## Model *(bắt buộc, một dòng)*
6
+
7
+ In model mà **bạn — agent vừa chạy lệnh này — thực sự đang dùng** (ghi nhận ở Gate Bước 0-B):
8
+
9
+ ```
10
+ Model: {tên model đang chạy}
11
+ ```
12
+
13
+ Nếu bạn biết mình **không** phải một model Opus, thêm cảnh báo ngay trên cùng dòng:
14
+
15
+ ```
16
+ Model: {tên model} ⚠️ lệnh này khuyến nghị Opus — model nhỏ hơn dễ bỏ sót edge case,
17
+ phân tích spec thiếu sót, vi phạm kiến trúc. Cân nhắc chạy lại
18
+ với /model → Opus trước khi dùng kết quả này.
19
+ ```
20
+
21
+ > **Vì sao ở ĐÂY chứ không phải một prompt ở đầu lệnh (GAPS-v3 G41):** trước đây Gate hiện
22
+ > `⚙️ MODEL CHECK` rồi chờ `Y/S/N`. Nó **hỏi người dùng thứ agent đã biết**, câu trả lời
23
+ > **không kiểm chứng được**, và **cả `Y` lẫn `S` đều đi tiếp** — tức không chặn được ai, mà
24
+ > tốn một lần chặn ở mọi lệnh (20 lệnh cho một feature). Khai báo ở footer đúng nguồn hơn
25
+ > (agent tự khai, không phải người tự khai) và đúng chỗ hơn: nó nằm **cạnh kết quả** để
26
+ > người đọc cân nhắc có nên tin, thay vì nằm trước khi có kết quả để bấm cho xong.
27
+
5
28
  ## Status Badge
6
29
 
7
30
  Chọn một theo kết quả:
@@ -34,7 +57,7 @@ Tìm lệnh hiện tại trong bảng phase dưới đây và đánh dấu **pha
34
57
  | Phase | Commands |
35
58
  |-------|----------|
36
59
  | Discovery | `/define-product` |
37
- | PRD | `/generate-prd` · `/refine-prd` · `/review-context` (PRD) |
60
+ | PRD | `/generate-prd` · `/extend-prd` · `/refine-prd` · `/review-context` (PRD) |
38
61
  | Design Spec | `/generate-design-spec` |
39
62
  | BDD | `/generate-bdd` · `/review-context` (BDD) |
40
63
  | Tech Design | `/generate-tech-docs` · `/map-testids` · `/review-tech-docs` |
@@ -59,6 +82,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
59
82
  | /setup-ai-first | `/define-product` để bắt đầu feature đầu tiên |
60
83
  | /define-product | `/generate-prd {product-definition-file}` |
61
84
  | /generate-prd | `/refine-prd {prd-file}` rồi `/review-context {prd-file}` |
85
+ | /extend-prd | `/refine-prd {prd-file}` (soi phần vừa thêm) rồi `/review-context {prd-file}` → PO duyệt → `/generate-bdd` **chỉ cho UC MỚI**; UC cũ dùng `/validate-traces --realign-prd-version {UC-ID}` |
62
86
  | /refine-prd | Mở Review Board → cập nhật PRD → `/review-context {prd-file}` |
63
87
  | /review-context (PRD) | Khi 0 critical → PO đặt `Status: approved`, rồi FE/App: `/generate-design-spec {prd-file}` (→ design sign-off → BDD); BE: `/generate-bdd {prd-file}`. Còn critical/NEEDS_FIX → sửa PRD (giữ draft) |
64
88
  | /generate-design-spec | Designer review → xác nhận link Figma → PO + Designer sign-off → `/generate-bdd {prd-file}` |
@@ -84,7 +108,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
84
108
  | /fix-bug | `/dev-run-test {UC-ID}` (dev_selftest vừa reset về not_run) → tạo PR; nếu fix một `{BUG-ID}` → QC chạy `/qc-run-test {UC-ID}` để verify + đóng bug |
85
109
  | /debug | `/fix-bug {ticket-id}` nếu cần sửa |
86
110
  | /report-bug | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
87
- | /propose-scenario | Báo PO/Dev review proposal trong `feedback/bdd-proposals/` |
111
+ | /propose-scenario | **Case A** (thiếu scenario cho AC có sẵn) → báo PO/Dev review trong `feedback/bdd-proposals/`; `/generate-bdd` tự chèn khi `Status: accepted`. **Case B** (requirement mới) → `feedback/prd-change-requests/` — PO phải đưa vào PRD trước, KHÔNG tự vào BDD được; `/validate-traces` nhắc lại kèm số ngày chờ chừng nào `Status: Open` |
88
112
  | /learn | Tiếp tục làm việc — lesson áp dụng ở lệnh kế tiếp |
89
113
  | /sync | `/validate-traces` để xem độ phủ đầy đủ; xử lý mọi `📥 tester feedback` được nêu |
90
114
  | /update-framework | Review `git diff .agent/`, commit; `/sync` để đồng bộ nội dung dự án |
@@ -1,7 +1,31 @@
1
- # Làm mới panel mirror của Living Docs *(local, chế độ umbrella)*
1
+ # Làm mới panel mirror của Living Docs *(local)*
2
2
 
3
- *Bỏ qua hoàn toàn chế độ single-service (không `services` không `setup.spec_source`) — đó
4
- `.trace/` của chính repo CHÍNH LÀ vị trí panel, nên không có gì để mirror.*
3
+ > **Hai vị trí, HAI TÊN KHÁC NHAU đọc trước khi sửa đây.**
4
+ >
5
+ > | Đường dẫn | Vai trò | Git |
6
+ > |---|---|---|
7
+ > | `{paths.trace_dir}` (`.trace/` hoặc `{spec_source}/.trace/`) | **AUTHORITATIVE** — TSV + `trace-history.jsonl`. Không regenerate được. | **PHẢI commit** |
8
+ > | `./.trace-mirror/` ở gốc workspace hiện tại | **MIRROR** — bản sao tiện cho panel VS Code. Sinh lại được bất cứ lúc nào. | **Luôn gitignore** |
9
+ >
10
+ > Trước v0.4.3 cả hai đều tên `.trace`, nên một luật gitignore theo tên có thể **xoá sạch sổ gốc**
11
+ > khi dev mở thẳng spec repo làm workspace (lúc đó hai path bằng nhau). Hai tên khác nhau làm
12
+ > luật git đọc được bằng mắt và **không còn ca nhập nhằng nào**: `.trace-mirror/` không bao giờ
13
+ > commit, `.trace/` không bao giờ gitignore.
14
+
15
+ ## Khi nào CÓ mirror
16
+
17
+ Mirror chỉ tồn tại khi **`{paths.trace_dir}` nằm NGOÀI workspace hiện tại** — panel đọc từ workspace đang mở nên cần một bản sao ở đây.
18
+
19
+ | Tình huống | `{paths.trace_dir}` | Có mirror? |
20
+ |---|---|---|
21
+ | Single-service | `./.trace` — **trong** workspace | ❌ Không. Panel đọc thẳng `.trace/trace-report.json`. Bỏ qua cả file này. |
22
+ | Dev mở thẳng **spec repo** | `./.trace` — **trong** workspace | ❌ Không. Như trên. |
23
+ | Umbrella + `spec_source`, dev đứng ở umbrella hoặc service submodule | `{spec_source}/.trace` — **ngoài** workspace | ✅ Có |
24
+ | Umbrella legacy (không `spec_source`) | `.trace` theo từng service | ✅ Có |
25
+
26
+ Quy tắc một dòng: **phân giải `panel_mirror = ./.trace-mirror` ở gốc workspace hiện tại; nếu `{paths.trace_dir}` đã nằm trong workspace này thì bỏ qua toàn bộ bước mirror.**
27
+
28
+ ---
5
29
 
6
30
  Sau khi cập nhật TSV authoritative tại `{paths.trace_dir}`:
7
31
 
@@ -9,11 +33,14 @@ Sau khi cập nhật TSV authoritative tại `{paths.trace_dir}`:
9
33
  `{paths.trace_dir}` phân giải về `{spec_source}/.trace` — vị trí authoritative duy nhất.
10
34
  Lệnh này chạy từ `service_root`, nên thao tác ghi là **liên-repo vào spec submodule**;
11
35
  commit/push spec submodule cho lần cập nhật trace (giống như `feedback/`).
12
- 1. Phân giải `panel_mirror = ./.trace` tại **gốc workspace hiện tại**.
13
- 2. Nếu `panel_mirror` phân giải ra path khác với `{paths.trace_dir}`, copy mỗi
36
+
37
+ 1. Phân giải `panel_mirror = ./.trace-mirror` tại **gốc workspace hiện tại**.
38
+ 2. Nếu `{paths.trace_dir}` **không** nằm trong workspace hiện tại, copy mỗi
14
39
  `{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{UC-ID}-{platform}.tsv` (tạo thư mục; ghi đè).
15
- Không namespace theo service — chỉ có một bộ trace; service sở hữu được mang trong
16
- `@trace.service` của từng row.
40
+ Không namespace theo service — chỉ có một bộ trace; service sở hữu được mang
41
+ **cột `service` (cột 23)** của chính từng row, do `/generate-bdd` ghi từ `@trace.service`.
42
+ 3. **KHÔNG copy `trace-history.jsonl`.** Nó là dữ liệu tích luỹ, không phải thứ sinh lại được —
43
+ nhân bản nó ra một thư mục gitignore là tạo hai lịch sử lệch nhau rồi mất bản thật.
17
44
 
18
45
  **Legacy (không có `spec_source` — trace theo service):**
19
46
  Copy mỗi `{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{service-name}/{UC-ID}-{platform}.tsv`
@@ -17,7 +17,28 @@ commands/generate-bdd.md
17
17
 
18
18
  Không lệnh nào đọc một path template lúc chạy. `paths.feature_template` / `paths.prd_template` từng tồn tại trong `project-context.yaml` nhưng chưa bao giờ có tác dụng — đã được gỡ bỏ (xem `GAPS.md` G9).
19
19
 
20
- **Thêm nữa:** `.agent/` là vùng bị ghi đè. `/update-framework` chạy `npx … --init`, và `--init` copy `core/` → `.agent/` **vô điều kiện** (`bin/index.js` → `copyDirRecursive`, không có existence check, không backup). File duy nhất được giữ lại là `.agent/project-context.yaml`. Nên mọi chỉnh sửa ở `.agent/templates/` sẽ **biến mất im lặng** ở lần nâng cấp kế tiếp.
20
+ **Thêm nữa:** `.agent/` là vùng bị ghi đè. `/update-framework` chạy `npx … --init`, và `--init` copy `core/` → `.agent/` **vô điều kiện** (`bin/index.js` → `installCore`). File duy nhất được giữ lại là `.agent/project-context.yaml`. Nên mọi chỉnh sửa ở `.agent/templates/` sẽ **biến mất** ở lần nâng cấp kế tiếp — từ v0.4.2 thì không còn im lặng: bản cũ được lưu vào `.agent/.overwritten-{version}-{date}/` và được liệt kê ra (`GAPS.md` G24). Nhưng vẫn phải áp lại bằng tay mỗi version, nên đây không phải chỗ để đặt thay đổi.
21
+
22
+ ---
23
+
24
+ ## Ngoại lệ: `ci/` và `hooks/` — template để COPY RA, không phải để build
25
+
26
+ Hai thư mục này **không** giống phần còn lại của `templates/`. Chúng không được `{{include}}` vào lệnh nào, và **không** được đọc lúc chạy. Chúng là file **hoàn chỉnh, dùng ngay**, chờ một người copy ra khỏi `.agent/`:
27
+
28
+ | File | Copy tới | Làm gì |
29
+ |---|---|---|
30
+ | `ci/trace-gate.yml` | `.github/workflows/` của project | Chặn PR khi trace có cờ 🔴 (`--gate-trace`) |
31
+ | `hooks/pre-push` | `.git/hooks/pre-push` (rồi `chmod +x`) | Chặn push khi sổ trace hỏng cấu trúc (`--lint-trace`) |
32
+
33
+ ```bash
34
+ # từ gốc project
35
+ mkdir -p .github/workflows && cp .agent/templates/ci/trace-gate.yml .github/workflows/
36
+ cp .agent/templates/hooks/pre-push .git/hooks/pre-push && chmod +x .git/hooks/pre-push
37
+ ```
38
+
39
+ **Phải copy RA, không dùng tại chỗ** — vì đúng cái lý do cả file README này nói: `.agent/` bị ghi đè mỗi lần nâng cấp, và `.git/hooks/` thì git không bao giờ chạy từ chỗ khác. Copy ra rồi thì chúng là file của project: sửa tuỳ ý, nâng cấp framework không đụng tới.
40
+
41
+ Vì sao chúng tồn tại → `GAPS-v3.md` G39: framework phát hiện được một lớp lỗi mà build xanh + test xanh không thấy, nhưng trước đó việc phát hiện phụ thuộc vào có người tự nguyện chạy một lệnh chat. Hai file này là chỗ nó chặn bằng máy.
21
42
 
22
43
  ## Muốn đổi cấu trúc artifact sinh ra thì làm gì
23
44
 
@@ -43,5 +64,7 @@ Rồi phát hành version mới; project chạy `/update-framework` để nhận
43
64
  | `product-definition.template.md` | `commands/define-product.tmpl` | product definition |
44
65
  | `platform-guide.template.md` | (tham khảo) | — |
45
66
  | `project-context.yaml` | **không** include — được copy thẳng làm file config khởi tạo | `.agent/project-context.yaml` |
67
+ | `ci/trace-gate.yml` | **không** include — người dùng copy ra | `.github/workflows/trace-gate.yml` |
68
+ | `hooks/pre-push` | **không** include — người dùng copy ra | `.git/hooks/pre-push` |
46
69
 
47
70
  > Lưu ý `project-context.yaml` là ngoại lệ duy nhất: nó **được** copy ra làm file thật của project, và **được bảo vệ** khỏi ghi đè khi nâng cấp (chỉ tạo nếu chưa tồn tại).
@@ -0,0 +1,146 @@
1
+ # ─────────────────────────────────────────────────────────────────────────────
2
+ # SDD Framework — Trace Gate (GitHub Actions)
3
+ #
4
+ # COPY file này vào .github/workflows/ của project. Nó KHÔNG tự chạy từ
5
+ # .agent/templates/ — mọi thứ trong .agent/ là bản sinh ra, bị ghi đè mỗi lần
6
+ # /update-framework.
7
+ #
8
+ # VÌ SAO CẦN (GAPS-v3 G39): framework phát hiện được một lớp lỗi mà build xanh +
9
+ # test từng-UC xanh KHÔNG thấy — luồng ghép chạy vào hàm rỗng (SEAM_UNWIRED,
10
+ # STUB_UNRESOLVED), hoặc code trỏ vào scenario đã bị xoá (ORPHANED, TRACE_ORPHAN).
11
+ # Nhưng trước G39 việc phát hiện đó phụ thuộc vào có người TỰ NGUYỆN chạy
12
+ # /validate-traces trong Claude Code rồi đọc report bằng mắt. Cái gì không chặn
13
+ # thì sau sprint thứ ba không ai làm. Đây là chỗ nó chặn.
14
+ #
15
+ # GIỚI HẠN — đọc trước khi tin:
16
+ # Job này chứng minh "report khớp SỔ, và sổ không có cờ 🔴".
17
+ # Nó KHÔNG chứng minh "sổ khớp CODE" — việc đó cần quét tag trong source, đọc
18
+ # .feature, so version, tức cần /validate-traces (một lệnh LLM, không chạy được
19
+ # trong CI thường). Nên nó bắt ca phổ biến "quên chạy lại /validate-traces",
20
+ # nhưng KHÔNG bắt ca "sửa code mà không đụng sổ".
21
+ # Muốn bịt nốt: xem job `require-fresh-audit` ở cuối file.
22
+ # ─────────────────────────────────────────────────────────────────────────────
23
+
24
+ name: Trace Gate
25
+
26
+ on:
27
+ pull_request:
28
+ push:
29
+ branches: [main, master, develop]
30
+
31
+ jobs:
32
+ trace-gate:
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ with:
37
+ # Cần lịch sử để job require-fresh-audit so được diff. Bỏ nếu không dùng job đó.
38
+ fetch-depth: 0
39
+ # Spec/trace nằm trong submodule (umbrella + spec_source)? Bỏ comment:
40
+ # submodules: recursive
41
+
42
+ - uses: actions/setup-node@v4
43
+ with:
44
+ node-version: '20'
45
+
46
+ # ── 1. Cấu trúc sổ ───────────────────────────────────────────────────────
47
+ # Sổ trace 24 cột do LLM ghi bằng tay. Một dấu tab thiếu dồn mọi ô sang trái
48
+ # và ô `status` nhận một ngày tháng — trước G38 không gì báo. Bước này chặn.
49
+ # Cũng bắt marker conflict git lọt vào sổ (T7) và sổ thiếu luật merge (T10).
50
+ - name: Lint sổ trace
51
+ run: npx -y @educa-corp/sdd-framework@latest --lint-trace
52
+
53
+ # ── 2. Cổng chặn PR ──────────────────────────────────────────────────────
54
+ # --gate-trace tự chạy lại lint ở tầng G1, nên bước 1 ở trên là để có log
55
+ # riêng dễ đọc khi đỏ. Muốn gọn thì bỏ bước 1 và chỉ giữ bước này.
56
+ - name: Trace gate (cờ 🔴 chặn PR)
57
+ run: npx -y @educa-corp/sdd-framework@latest --gate-trace
58
+
59
+ # ── 3. (tuỳ chọn) Đưa kết quả vào PR summary ─────────────────────────────
60
+ - name: Ghi kết quả vào job summary
61
+ if: always()
62
+ run: |
63
+ npx -y @educa-corp/sdd-framework@latest --gate-trace --json --warn-only \
64
+ > gate.json || true
65
+ {
66
+ echo '## Trace Gate'
67
+ echo '```json'
68
+ cat gate.json
69
+ echo '```'
70
+ } >> "$GITHUB_STEP_SUMMARY"
71
+
72
+ # ───────────────────────────────────────────────────────────────────────────
73
+ # Ép audit phải TƯƠI khi thứ report đang KHẲNG ĐỊNH bị đổi.
74
+ #
75
+ # Bịt cái lỗ mà trace-gate không bịt được: gate chứng minh "report khớp SỔ",
76
+ # không chứng minh "sổ khớp CODE" — việc đó cần /validate-traces, một lệnh LLM
77
+ # không chạy được ở đây. Nên job này dùng một PROXY: không verify được thì ĐÒI
78
+ # BẰNG CHỨNG có người vừa verify.
79
+ #
80
+ # ĐO BẰNG TAG, KHÔNG BẰNG `src/**`:
81
+ # Framework có luật boundary-only tagging — chỉ Controller/Handler/Middleware/
82
+ # Steps mang tag @trace; Entity/Repository/DTO/Interface/Base KHÔNG. Nên câu
83
+ # hỏi "PR có sửa src/ không?" chặn cả PR chỉ thêm một field vào DTO — một file
84
+ # không mang lời khẳng định trace nào. Cái gì báo oan thì bị tắt, rồi mất luôn
85
+ # phần thật sự cần chặn.
86
+ # Câu hỏi đúng: "PR có chạm dòng nào mang tag mà report đang khẳng định không?"
87
+ #
88
+ # sửa log trong Controller → cho qua (bản `src/**` cũ: chặn oan)
89
+ # thêm field vào DTO → cho qua (bản cũ: chặn oan)
90
+ # thêm method + @implements → CHẶN
91
+ # lấp một @trace.stub → CHẶN
92
+ #
93
+ # KHÔNG cần sửa gì theo layout project — tag là tag, ở đâu cũng vậy.
94
+ #
95
+ # BẢY TAG dưới đây là NGUỒN của đúng 4 cờ chặn PR. Chúng được khai trong
96
+ # bin/trace-schema.json → gate.audit_invalidating_tags, và self-check R10 fail
97
+ # build nếu file này không nhắc đủ — tag đổi tên mà đây không biết thì grep
98
+ # không khớp gì, job LUÔN XANH, và cổng mù trong im lặng.
99
+ #
100
+ # GIỚI HẠN ĐÃ BIẾT: đổi tên class (AuthService → AuthenticationService) không
101
+ # chạm dòng tag ⇒ job này bỏ lọt, dù cột implemented_by giờ trỏ vào tên không
102
+ # còn. Chấp nhận có chủ ý: ca đó ít gặp và KHÔNG im lặng (/validate-traces lần
103
+ # sau báo ngay), còn báo oan thì xảy ra mỗi ngày.
104
+ # Muốn chặt hơn (bắt cả rename, giá là chặn cả việc sửa log trong Controller):
105
+ # đổi bước dưới thành — lấy danh sách file đã đổi, rồi `grep -l` bảy tag đó
106
+ # TRÊN NỘI DUNG FILE thay vì trên diff.
107
+ # ───────────────────────────────────────────────────────────────────────────
108
+ require-fresh-audit:
109
+ if: github.event_name == 'pull_request'
110
+ runs-on: ubuntu-latest
111
+ steps:
112
+ - uses: actions/checkout@v4
113
+ with: { fetch-depth: 0 }
114
+
115
+ - name: Đổi thứ report khẳng định thì audit phải đổi theo
116
+ shell: bash
117
+ run: |
118
+ BASE="origin/${{ github.base_ref }}"
119
+
120
+ # 7 tag sinh ra 4 cờ chặn PR — khai ở bin/trace-schema.json,
121
+ # gate.audit_invalidating_tags (self-check R10 canh danh sách này khớp).
122
+ TAGS='@trace\.(implements|verifies|seam_port|seam_pending|stub|stub_owner|stub_for)'
123
+
124
+ # Chạm dòng mang tag = report có thể đã hết đúng. -U0 để chỉ lấy dòng thật đổi.
125
+ touched=$(git diff -U0 "$BASE"...HEAD | grep -E "^[+-].*${TAGS}" | head -5 || true)
126
+ audit=$(git diff --name-only "$BASE"...HEAD | grep -E 'trace-report\.json$' | head -1 || true)
127
+
128
+ if [ -n "$touched" ] && [ -z "$audit" ]; then
129
+ echo "::error::PR đổi tag trace nhưng không kèm trace-report.json được sinh lại."
130
+ echo ""
131
+ echo "Những dòng này đã đổi:"
132
+ echo "$touched" | sed 's/^/ /'
133
+ echo ""
134
+ echo "Trace gate chỉ chứng minh 'report khớp SỔ'. Tag vừa đổi mà chưa audit lại"
135
+ echo "thì mọi cờ 🔴 trong report nói về trạng thái TRƯỚC khi bạn sửa."
136
+ echo ""
137
+ echo "Chạy trong Claude Code: /validate-traces"
138
+ echo "Rồi commit: {trace_dir}/trace-report.json + *.tsv"
139
+ exit 1
140
+ fi
141
+
142
+ if [ -n "$touched" ]; then
143
+ echo "✅ Tag trace có đổi, và audit đã được sinh lại cùng PR."
144
+ else
145
+ echo "✅ PR không chạm tag nào mà report đang khẳng định — audit vẫn còn đúng."
146
+ fi
@@ -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ỏ trong spec repo mode}
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}
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
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env sh
2
+ # ─────────────────────────────────────────────────────────────────────────────
3
+ # SDD Framework — git pre-push hook
4
+ #
5
+ # CÀI (từ gốc project):
6
+ # cp .agent/templates/hooks/pre-push .git/hooks/pre-push
7
+ # chmod +x .git/hooks/pre-push
8
+ #
9
+ # Trên Windows: Git for Windows chạy hook bằng sh nên file này dùng được như vậy.
10
+ #
11
+ # VÌ SAO CÓ HOOK NÀY khi đã có CI (GAPS-v3 G39/G40): nó chặn ở chỗ RẺ NHẤT.
12
+ # Cụ thể là T7 — marker conflict git (`<<<<<<< HEAD`) lọt vào sổ trace. Một khi
13
+ # thứ đó vào nhánh chung thì mọi người kéo về đều có sổ hỏng, và sổ trace là dữ
14
+ # liệu KHÔNG dựng lại được. Bắt trước lúc push tốn 2 giây; bắt ở CI thì đã muộn
15
+ # một vòng, bắt bằng mắt thì thường là ba tuần sau.
16
+ #
17
+ # CỐ Ý CHỈ LINT, KHÔNG GATE:
18
+ # --lint-trace = cấu trúc sổ. Nhanh, offline được sau lần đầu, và một lỗi ở đây
19
+ # LUÔN là lỗi thật (tab lệch, marker conflict, enum sai).
20
+ # --gate-trace = cờ 🔴. Cần trace-report.json còn tươi, mà giữa lúc làm việc thì
21
+ # nó thường chưa tươi — đỏ liên tục ⇒ người ta gõ --no-verify ⇒
22
+ # mất luôn cả phần lint. Cờ 🔴 để CI chặn.
23
+ #
24
+ # Bỏ qua một lần (dùng có ý thức, đừng thành phản xạ): git push --no-verify
25
+ # ─────────────────────────────────────────────────────────────────────────────
26
+
27
+ # Không có node thì im lặng cho qua — hook không được làm người ta không push được
28
+ # vì lý do không liên quan tới việc họ đang làm.
29
+ command -v node >/dev/null 2>&1 || exit 0
30
+
31
+ # Không có sổ trace thì không có gì để kiểm (project chưa chạy /generate-bdd lần nào).
32
+ # Sửa đường dẫn nếu trace_dir của project khác (vd ../.trace, hay {spec_source}/.trace).
33
+ TRACE_DIR=".trace"
34
+ [ -d "$TRACE_DIR" ] || exit 0
35
+
36
+ echo "→ Lint sổ trace trước khi push ..."
37
+
38
+ if npx -y @educa-corp/sdd-framework@latest --lint-trace --trace "$TRACE_DIR"; then
39
+ exit 0
40
+ fi
41
+
42
+ cat <<'MSG'
43
+
44
+ ──────────────────────────────────────────────────────────────────────
45
+ 🔴 PUSH BỊ CHẶN — sổ trace hỏng cấu trúc.
46
+
47
+ Sổ trace là dữ liệu KHÔNG regenerate được. Đẩy một sổ hỏng lên nhánh
48
+ chung thì mọi người kéo về đều nhận bản hỏng.
49
+
50
+ Thường gặp nhất — marker conflict git chưa giải (T7):
51
+ 1. Mở file lint vừa nêu, xoá 3 dòng <<<<<<< ======= >>>>>>>
52
+ 2. GIỮ CẢ HAI BÊN, đừng chọn một bên (mất row là mất vĩnh viễn)
53
+ 3. npx @educa-corp/sdd-framework --lint-trace # xác nhận sạch
54
+ 4. /validate-traces trong Claude Code # reconcile row trùng
55
+
56
+ Playbook đầy đủ: docs/02-concepts/traceability.md
57
+ Bỏ qua một lần: git push --no-verify
58
+ ──────────────────────────────────────────────────────────────────────
59
+
60
+ MSG
61
+ exit 1
@@ -77,12 +77,29 @@ AI *follow* các file này — để trống thì nó *đoán*:
77
77
 
78
78
  | Lệnh | Việc | Ghi đè | KHÔNG đụng |
79
79
  |------|------|--------|-----------|
80
- | `/update-framework` | Sync bản npm mới | `.agent/commands\|steps\|hooks\|rules\|templates\|skills\|modules` | `CLAUDE.md`, `project-context.yaml`, `domain-knowledge/`, `.trace/` |
80
+ | `/update-framework` | Sync bản npm mới | `.agent/commands\|steps\|hooks\|rules\|templates\|skills\|modules` | `CLAUDE.md`, `.agent/project-context.yaml`, `.agent/project-lessons.md`, `.agent/review/`, `domain-knowledge/`, `.trace/`, `feedback/` |
81
81
  | `/sync` (umbrella) | Pull + init submodule + nổi feedback + Living Docs | — | — |
82
82
 
83
83
  Kiểm tra version mới nhất: `npm view @educa-corp/sdd-framework version`.
84
84
 
85
85
  > **Quy tắc edit (critical):** `.tmpl` + `steps/` là source of truth. Sửa framework artifact phải sửa `.tmpl`/`steps` rồi `node bin/build.js`. Sửa thẳng `.agent/commands/*.md` sẽ **mất** khi rebuild/update.
86
+ >
87
+ > Từ v0.4.2, nâng cấp **cứu** file bạn đã sửa trong vùng ghi đè: bản cũ lưu ở `.agent/.overwritten-{version}-{date}/` và danh sách được in ra. Ranh giới vùng-sửa-được đầy đủ: `.agent/README.md`. Chi tiết cơ chế: [Configuration › Vùng nào bị ghi đè](../04-reference/configuration.md#vùng-nào-bị-ghi-đè-khi-update).
88
+
89
+ ### Migration bố cục spec
90
+
91
+ Một số version đổi **bố cục** chứ không chỉ nội dung lệnh. `/update-framework` Step 5.5 tự quét và nhắc, hoặc chạy tay (đều **dry-run mặc định**, thêm `--apply` để thực thi):
92
+
93
+ | Lệnh | Khi nào cần |
94
+ |---|---|
95
+ | `--migrate-bdd-platform` | Có `.feature` nằm **trực tiếp** dưới `bdd/` (bố cục phẳng trước v0.4.1) → chuyển sang `bdd/{platform}/`. Bố cục phẳng làm `web`/`system` cùng UC **va tên và ghi đè nhau**. |
96
+ | `--migrate-specs` | Còn `specs/prd/` hay `specs/bdd/` ở cấp gốc (bố cục artifact-type-first rất cũ) |
97
+ | `--rename-prd-files` | PRD còn tên cố định `prd.md` thay vì `{TICKET-ID}-{prd-slug}.md` |
98
+
99
+ ```bash
100
+ npx @educa-corp/sdd-framework --migrate-bdd-platform # xem plan
101
+ npx @educa-corp/sdd-framework --migrate-bdd-platform --apply # thực thi
102
+ ```
86
103
 
87
104
  ---
88
105
 
@@ -26,8 +26,10 @@ Dùng AI tự do (mở chat, gõ prompt, copy-paste) → AI suy diễn theo tr
26
26
  | Vấn đề | Cách giải |
27
27
  |--------|-----------|
28
28
  | AI viết lung tung, không bám requirement | Spec là **anchor cứng**; code link `@trace.source` về scenario |
29
- | Sửa code → spec lệch → AI hiểu sai lần sau | **Spec là single source of truth**; code không lưu version riêng |
30
- | Sửa spec → không biết code nào cần regen | **Trace state `.tsv` per-UC** phát hiện OK/GAP/DRIFT/UNTRACKED |
29
+ | Sửa code → spec lệch → AI hiểu sai lần sau | **Spec là SSOT của "bản hiện tại"**; code mang version của "bản tôi được sinh theo" — **lệch nhau chính là tín hiệu drift** |
30
+ | Sửa spec → không biết code nào cần regen | **Trace state `.tsv`** một sổ / UC × platform `OK`/`GAP`/`DRIFT`/`UNTRACKED`/`ORPHANED` |
31
+ | Xoá scenario → code mồ côi nằm im | **Quét ngược code → spec**; code trỏ vào SC không còn tồn tại bị gắn cờ 🔴, không tự hết |
32
+ | Build xanh nhưng ghép luồng chạy vào no-op | **Sổ seam/stub** — bắt lớp lỗi mà build + test từng-UC không thấy |
31
33
  | PRD/BDD kém → code rác hàng loạt | **Quality gate** (`/review-context`) phải sạch critical + PO approve |
32
34
  | Lỗi/định hướng sai lặp lại | **`/learn`** ghi lesson, nạp lại vào context |
33
35
  | Đổi tech stack → viết lại workflow | **Module overlay** — skill đọc `stack-profile.yaml`, không hardcode |