@educa-corp/sdd-framework 0.2.0 → 0.2.3

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 (67) hide show
  1. package/bin/index.js +59 -29
  2. package/commands/debug.md +21 -8
  3. package/commands/define-product.md +21 -8
  4. package/commands/dev-gen-test.md +21 -8
  5. package/commands/dev-run-test.md +21 -8
  6. package/commands/dev-smoke-test.md +21 -8
  7. package/commands/fix-bug.md +21 -8
  8. package/commands/generate-bdd.md +24 -10
  9. package/commands/generate-bdd.tmpl +3 -2
  10. package/commands/generate-code.md +21 -8
  11. package/commands/generate-design-spec.md +21 -8
  12. package/commands/generate-prd.md +21 -8
  13. package/commands/generate-spec-manifest.md +21 -8
  14. package/commands/generate-tech-docs.md +21 -8
  15. package/commands/learn.md +21 -8
  16. package/commands/map-testids.md +21 -8
  17. package/commands/propose-scenario.md +21 -8
  18. package/commands/qc-analyze.md +21 -8
  19. package/commands/qc-design-test.md +21 -8
  20. package/commands/qc-plan.md +21 -8
  21. package/commands/qc-report.md +21 -8
  22. package/commands/qc-review.md +21 -8
  23. package/commands/qc-run-test.md +21 -8
  24. package/commands/refine-prd.md +21 -8
  25. package/commands/report-bug.md +21 -8
  26. package/commands/review-code.md +21 -8
  27. package/commands/review-context.md +21 -8
  28. package/commands/review-tech-docs.md +21 -8
  29. package/commands/setup-ai-first.md +14 -7
  30. package/commands/setup-ai-first.tmpl +14 -7
  31. package/commands/validate-traces.md +21 -8
  32. package/core/FRAMEWORK_VERSION +1 -1
  33. package/core/commands/debug.md +21 -8
  34. package/core/commands/define-product.md +21 -8
  35. package/core/commands/dev-gen-test.md +21 -8
  36. package/core/commands/dev-run-test.md +21 -8
  37. package/core/commands/dev-smoke-test.md +21 -8
  38. package/core/commands/fix-bug.md +21 -8
  39. package/core/commands/generate-bdd.md +24 -10
  40. package/core/commands/generate-code.md +21 -8
  41. package/core/commands/generate-design-spec.md +21 -8
  42. package/core/commands/generate-prd.md +21 -8
  43. package/core/commands/generate-spec-manifest.md +21 -8
  44. package/core/commands/generate-tech-docs.md +21 -8
  45. package/core/commands/learn.md +21 -8
  46. package/core/commands/map-testids.md +21 -8
  47. package/core/commands/propose-scenario.md +21 -8
  48. package/core/commands/qc-analyze.md +21 -8
  49. package/core/commands/qc-design-test.md +21 -8
  50. package/core/commands/qc-plan.md +21 -8
  51. package/core/commands/qc-report.md +21 -8
  52. package/core/commands/qc-review.md +21 -8
  53. package/core/commands/qc-run-test.md +21 -8
  54. package/core/commands/refine-prd.md +21 -8
  55. package/core/commands/report-bug.md +21 -8
  56. package/core/commands/review-code.md +21 -8
  57. package/core/commands/review-context.md +21 -8
  58. package/core/commands/review-tech-docs.md +21 -8
  59. package/core/commands/setup-ai-first.md +14 -7
  60. package/core/commands/validate-traces.md +21 -8
  61. package/core/steps/context-loader.md +21 -8
  62. package/core/templates/project-context.yaml +24 -11
  63. package/docs/README.md +1 -1
  64. package/package.json +1 -1
  65. package/steps/context-loader.md +21 -8
  66. package/templates/project-context.yaml +24 -11
  67. package/readme.txt +0 -1
@@ -179,16 +179,28 @@ Nếu có section `services`:
179
179
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
180
180
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
181
181
 
182
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
183
- - Override `paths.specs_dir` `services.{domain}.specs_dir` **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
184
- - Override `paths.tech_docs_dir` `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract)artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` KHÔNG pin theo service ở đây.
182
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
183
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
184
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
185
+ - Nếu vẫn không xác định được → `active_platform = null`.
186
+
187
+ **2. Route tới service** — nếu active domain khớp một key trong `services`. Giá trị `services.{domain}` có **hai dạng**; nhận dạng bằng việc có `path` trực tiếp hay không:
188
+
189
+ **2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
185
190
  - Lưu `active_service` = `services.{domain}.path`
186
191
  - Lưu `active_service_module` = `services.{domain}.module`
187
192
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
188
193
 
189
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
190
- - Giữ path mặc định từ Bước 1
191
- - Đặt `active_service = unresolved`
194
+ **2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là `{ path, module }` (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
195
+ - Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
196
+ - Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi` và lưu `service_candidates = services.{domain}` (toàn map platform→{path,module}). Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
197
+ - Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
198
+
199
+ *(Cả 2a/2b: 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.)*
200
+
201
+ **3. Fallback**:
202
+ - 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`.
203
+ - 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 lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
192
204
 
193
205
  **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:`:
194
206
  - 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`.)*
@@ -208,7 +220,7 @@ Nếu có section `services`:
208
220
 
209
221
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
210
222
 
211
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
223
+ *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
212
224
 
213
225
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
214
226
 
@@ -384,7 +396,8 @@ Ticket : {ticket_prefix}-
384
396
  Dict : {loaded — N canonical terms, M banned terms | missing}
385
397
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
386
398
  Lessons : {loaded — N guardrails | chưa có}
387
- Service : {active_service} ({active_service_module}) | single-service
399
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
400
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
388
401
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
389
402
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
390
403
  ```
@@ -179,16 +179,28 @@ Nếu có section `services`:
179
179
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
180
180
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
181
181
 
182
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
183
- - Override `paths.specs_dir` `services.{domain}.specs_dir` **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
184
- - Override `paths.tech_docs_dir` `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract)artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` KHÔNG pin theo service ở đây.
182
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
183
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
184
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
185
+ - Nếu vẫn không xác định được → `active_platform = null`.
186
+
187
+ **2. Route tới service** — nếu active domain khớp một key trong `services`. Giá trị `services.{domain}` có **hai dạng**; nhận dạng bằng việc có `path` trực tiếp hay không:
188
+
189
+ **2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
185
190
  - Lưu `active_service` = `services.{domain}.path`
186
191
  - Lưu `active_service_module` = `services.{domain}.module`
187
192
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
188
193
 
189
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
190
- - Giữ path mặc định từ Bước 1
191
- - Đặt `active_service = unresolved`
194
+ **2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là `{ path, module }` (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
195
+ - Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
196
+ - Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi` và lưu `service_candidates = services.{domain}` (toàn map platform→{path,module}). Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
197
+ - Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
198
+
199
+ *(Cả 2a/2b: 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.)*
200
+
201
+ **3. Fallback**:
202
+ - 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`.
203
+ - 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 lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
192
204
 
193
205
  **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:`:
194
206
  - 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`.)*
@@ -208,7 +220,7 @@ Nếu có section `services`:
208
220
 
209
221
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
210
222
 
211
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
223
+ *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
212
224
 
213
225
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
214
226
 
@@ -384,7 +396,8 @@ Ticket : {ticket_prefix}-
384
396
  Dict : {loaded — N canonical terms, M banned terms | missing}
385
397
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
386
398
  Lessons : {loaded — N guardrails | chưa có}
387
- Service : {active_service} ({active_service_module}) | single-service
399
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
400
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
388
401
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
389
402
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
390
403
  ```
@@ -179,16 +179,28 @@ Nếu có section `services`:
179
179
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
180
180
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
181
181
 
182
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
183
- - Override `paths.specs_dir` `services.{domain}.specs_dir` **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
184
- - Override `paths.tech_docs_dir` `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract)artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` KHÔNG pin theo service ở đây.
182
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
183
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
184
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
185
+ - Nếu vẫn không xác định được → `active_platform = null`.
186
+
187
+ **2. Route tới service** — nếu active domain khớp một key trong `services`. Giá trị `services.{domain}` có **hai dạng**; nhận dạng bằng việc có `path` trực tiếp hay không:
188
+
189
+ **2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
185
190
  - Lưu `active_service` = `services.{domain}.path`
186
191
  - Lưu `active_service_module` = `services.{domain}.module`
187
192
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
188
193
 
189
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
190
- - Giữ path mặc định từ Bước 1
191
- - Đặt `active_service = unresolved`
194
+ **2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là `{ path, module }` (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
195
+ - Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
196
+ - Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi` và lưu `service_candidates = services.{domain}` (toàn map platform→{path,module}). Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
197
+ - Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
198
+
199
+ *(Cả 2a/2b: 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.)*
200
+
201
+ **3. Fallback**:
202
+ - 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`.
203
+ - 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 lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
192
204
 
193
205
  **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:`:
194
206
  - 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`.)*
@@ -208,7 +220,7 @@ Nếu có section `services`:
208
220
 
209
221
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
210
222
 
211
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
223
+ *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
212
224
 
213
225
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
214
226
 
@@ -384,7 +396,8 @@ Ticket : {ticket_prefix}-
384
396
  Dict : {loaded — N canonical terms, M banned terms | missing}
385
397
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
386
398
  Lessons : {loaded — N guardrails | chưa có}
387
- Service : {active_service} ({active_service_module}) | single-service
399
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
400
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
388
401
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
389
402
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
390
403
  ```
@@ -184,16 +184,28 @@ Nếu có section `services`:
184
184
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
185
185
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
186
186
 
187
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
188
- - Override `paths.specs_dir` `services.{domain}.specs_dir` **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
189
- - Override `paths.tech_docs_dir` `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract)artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` KHÔNG pin theo service ở đây.
187
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
188
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
189
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
190
+ - Nếu vẫn không xác định được → `active_platform = null`.
191
+
192
+ **2. Route tới service** — nếu active domain khớp một key trong `services`. Giá trị `services.{domain}` có **hai dạng**; nhận dạng bằng việc có `path` trực tiếp hay không:
193
+
194
+ **2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
190
195
  - Lưu `active_service` = `services.{domain}.path`
191
196
  - Lưu `active_service_module` = `services.{domain}.module`
192
197
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
193
198
 
194
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
195
- - Giữ path mặc định từ Bước 1
196
- - Đặt `active_service = unresolved`
199
+ **2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là `{ path, module }` (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
200
+ - Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
201
+ - Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi` và lưu `service_candidates = services.{domain}` (toàn map platform→{path,module}). Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
202
+ - Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
203
+
204
+ *(Cả 2a/2b: 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.)*
205
+
206
+ **3. Fallback**:
207
+ - 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`.
208
+ - 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 lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
197
209
 
198
210
  **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:`:
199
211
  - 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`.)*
@@ -213,7 +225,7 @@ Nếu có section `services`:
213
225
 
214
226
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
215
227
 
216
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
228
+ *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
217
229
 
218
230
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
219
231
 
@@ -389,7 +401,8 @@ Ticket : {ticket_prefix}-
389
401
  Dict : {loaded — N canonical terms, M banned terms | missing}
390
402
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
391
403
  Lessons : {loaded — N guardrails | chưa có}
392
- Service : {active_service} ({active_service_module}) | single-service
404
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
405
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
393
406
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
394
407
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
395
408
  ```
@@ -191,16 +191,28 @@ Nếu có section `services`:
191
191
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
192
192
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
193
193
 
194
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
195
- - Override `paths.specs_dir` `services.{domain}.specs_dir` **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
196
- - Override `paths.tech_docs_dir` `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract)artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` KHÔNG pin theo service ở đây.
194
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
195
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
196
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
197
+ - Nếu vẫn không xác định được → `active_platform = null`.
198
+
199
+ **2. Route tới service** — nếu active domain khớp một key trong `services`. Giá trị `services.{domain}` có **hai dạng**; nhận dạng bằng việc có `path` trực tiếp hay không:
200
+
201
+ **2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
197
202
  - Lưu `active_service` = `services.{domain}.path`
198
203
  - Lưu `active_service_module` = `services.{domain}.module`
199
204
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
200
205
 
201
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
202
- - Giữ path mặc định từ Bước 1
203
- - Đặt `active_service = unresolved`
206
+ **2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là `{ path, module }` (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
207
+ - Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
208
+ - Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi` và lưu `service_candidates = services.{domain}` (toàn map platform→{path,module}). Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
209
+ - Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
210
+
211
+ *(Cả 2a/2b: 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.)*
212
+
213
+ **3. Fallback**:
214
+ - 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`.
215
+ - 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 lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
204
216
 
205
217
  **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:`:
206
218
  - 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`.)*
@@ -220,7 +232,7 @@ Nếu có section `services`:
220
232
 
221
233
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
222
234
 
223
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
235
+ *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
224
236
 
225
237
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
226
238
 
@@ -396,7 +408,8 @@ Ticket : {ticket_prefix}-
396
408
  Dict : {loaded — N canonical terms, M banned terms | missing}
397
409
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
398
410
  Lessons : {loaded — N guardrails | chưa có}
399
- Service : {active_service} ({active_service_module}) | single-service
411
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
412
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
400
413
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
401
414
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
402
415
  ```
package/commands/learn.md CHANGED
@@ -188,16 +188,28 @@ Nếu có section `services`:
188
188
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
189
189
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
190
190
 
191
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
192
- - Override `paths.specs_dir` `services.{domain}.specs_dir` **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
193
- - Override `paths.tech_docs_dir` `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract)artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` KHÔNG pin theo service ở đây.
191
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
192
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
193
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
194
+ - Nếu vẫn không xác định được → `active_platform = null`.
195
+
196
+ **2. Route tới service** — nếu active domain khớp một key trong `services`. Giá trị `services.{domain}` có **hai dạng**; nhận dạng bằng việc có `path` trực tiếp hay không:
197
+
198
+ **2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
194
199
  - Lưu `active_service` = `services.{domain}.path`
195
200
  - Lưu `active_service_module` = `services.{domain}.module`
196
201
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
197
202
 
198
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
199
- - Giữ path mặc định từ Bước 1
200
- - Đặt `active_service = unresolved`
203
+ **2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là `{ path, module }` (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
204
+ - Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
205
+ - Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi` và lưu `service_candidates = services.{domain}` (toàn map platform→{path,module}). Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
206
+ - Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
207
+
208
+ *(Cả 2a/2b: 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.)*
209
+
210
+ **3. Fallback**:
211
+ - 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`.
212
+ - 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 lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
201
213
 
202
214
  **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:`:
203
215
  - 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`.)*
@@ -217,7 +229,7 @@ Nếu có section `services`:
217
229
 
218
230
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
219
231
 
220
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
232
+ *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
221
233
 
222
234
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
223
235
 
@@ -393,7 +405,8 @@ Ticket : {ticket_prefix}-
393
405
  Dict : {loaded — N canonical terms, M banned terms | missing}
394
406
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
395
407
  Lessons : {loaded — N guardrails | chưa có}
396
- Service : {active_service} ({active_service_module}) | single-service
408
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
409
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
397
410
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
398
411
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
399
412
  ```
@@ -189,16 +189,28 @@ Nếu có section `services`:
189
189
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
190
190
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
191
191
 
192
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
193
- - Override `paths.specs_dir` `services.{domain}.specs_dir` **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
194
- - Override `paths.tech_docs_dir` `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract)artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` KHÔNG pin theo service ở đây.
192
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
193
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
194
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
195
+ - Nếu vẫn không xác định được → `active_platform = null`.
196
+
197
+ **2. Route tới service** — nếu active domain khớp một key trong `services`. Giá trị `services.{domain}` có **hai dạng**; nhận dạng bằng việc có `path` trực tiếp hay không:
198
+
199
+ **2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
195
200
  - Lưu `active_service` = `services.{domain}.path`
196
201
  - Lưu `active_service_module` = `services.{domain}.module`
197
202
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
198
203
 
199
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
200
- - Giữ path mặc định từ Bước 1
201
- - Đặt `active_service = unresolved`
204
+ **2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là `{ path, module }` (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
205
+ - Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
206
+ - Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi` và lưu `service_candidates = services.{domain}` (toàn map platform→{path,module}). Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
207
+ - Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
208
+
209
+ *(Cả 2a/2b: 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.)*
210
+
211
+ **3. Fallback**:
212
+ - 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`.
213
+ - 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 lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
202
214
 
203
215
  **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:`:
204
216
  - 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`.)*
@@ -218,7 +230,7 @@ Nếu có section `services`:
218
230
 
219
231
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
220
232
 
221
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
233
+ *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
222
234
 
223
235
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
224
236
 
@@ -394,7 +406,8 @@ Ticket : {ticket_prefix}-
394
406
  Dict : {loaded — N canonical terms, M banned terms | missing}
395
407
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
396
408
  Lessons : {loaded — N guardrails | chưa có}
397
- Service : {active_service} ({active_service_module}) | single-service
409
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
410
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
398
411
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
399
412
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
400
413
  ```
@@ -189,16 +189,28 @@ Nếu có section `services`:
189
189
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
190
190
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
191
191
 
192
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
193
- - Override `paths.specs_dir` `services.{domain}.specs_dir` **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
194
- - Override `paths.tech_docs_dir` `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract)artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` KHÔNG pin theo service ở đây.
192
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
193
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
194
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
195
+ - Nếu vẫn không xác định được → `active_platform = null`.
196
+
197
+ **2. Route tới service** — nếu active domain khớp một key trong `services`. Giá trị `services.{domain}` có **hai dạng**; nhận dạng bằng việc có `path` trực tiếp hay không:
198
+
199
+ **2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
195
200
  - Lưu `active_service` = `services.{domain}.path`
196
201
  - Lưu `active_service_module` = `services.{domain}.module`
197
202
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
198
203
 
199
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
200
- - Giữ path mặc định từ Bước 1
201
- - Đặt `active_service = unresolved`
204
+ **2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là `{ path, module }` (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
205
+ - Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
206
+ - Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi` và lưu `service_candidates = services.{domain}` (toàn map platform→{path,module}). Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
207
+ - Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
208
+
209
+ *(Cả 2a/2b: 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.)*
210
+
211
+ **3. Fallback**:
212
+ - 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`.
213
+ - 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 lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
202
214
 
203
215
  **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:`:
204
216
  - 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`.)*
@@ -218,7 +230,7 @@ Nếu có section `services`:
218
230
 
219
231
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
220
232
 
221
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
233
+ *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
222
234
 
223
235
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
224
236
 
@@ -394,7 +406,8 @@ Ticket : {ticket_prefix}-
394
406
  Dict : {loaded — N canonical terms, M banned terms | missing}
395
407
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
396
408
  Lessons : {loaded — N guardrails | chưa có}
397
- Service : {active_service} ({active_service_module}) | single-service
409
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
410
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
398
411
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
399
412
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
400
413
  ```
@@ -187,16 +187,28 @@ Nếu có section `services`:
187
187
  *(vd: `specs/user/create-account/USR01-create-account.md` **và** `specs/user/create-account/bdd/system/UC1.feature` đều → domain = `user`, prd_slug = `create-account`)*
188
188
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
189
189
 
190
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
191
- - Override `paths.specs_dir` `services.{domain}.specs_dir` **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, MỌI BDD (web/app/**system**) artifact dùng chung liên team → để bước 4 route sang spec repo; KHÔNG pin theo service ở đây.
192
- - Override `paths.tech_docs_dir` `services.{domain}.tech_docs_dir` — **chỉ khi `setup.spec_source` KHÔNG được đặt.** Khi `spec_source` ĐƯỢC đặt, tech-design (API contract)artifact liên team và phải nằm trong spec repo dùng chung (xử lý ở bước 4), nên để bước 4 route `tech_docs_dir` KHÔNG pin theo service ở đây.
190
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
191
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
192
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
193
+ - Nếu vẫn không xác định được → `active_platform = null`.
194
+
195
+ **2. Route tới service** — nếu active domain khớp một key trong `services`. Giá trị `services.{domain}` có **hai dạng**; nhận dạng bằng việc có `path` trực tiếp hay không:
196
+
197
+ **2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
193
198
  - Lưu `active_service` = `services.{domain}.path`
194
199
  - Lưu `active_service_module` = `services.{domain}.module`
195
200
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
196
201
 
197
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
198
- - Giữ path mặc định từ Bước 1
199
- - Đặt `active_service = unresolved`
202
+ **2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là `{ path, module }` (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
203
+ - Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
204
+ - Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi` và lưu `service_candidates = services.{domain}` (toàn map platform→{path,module}). Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
205
+ - Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
206
+
207
+ *(Cả 2a/2b: 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.)*
208
+
209
+ **3. Fallback**:
210
+ - 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`.
211
+ - 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 lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
200
212
 
201
213
  **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:`:
202
214
  - 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`.)*
@@ -216,7 +228,7 @@ Nếu có section `services`:
216
228
 
217
229
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
218
230
 
219
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
231
+ *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
220
232
 
221
233
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
222
234
 
@@ -392,7 +404,8 @@ Ticket : {ticket_prefix}-
392
404
  Dict : {loaded — N canonical terms, M banned terms | missing}
393
405
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
394
406
  Lessons : {loaded — N guardrails | chưa có}
395
- Service : {active_service} ({active_service_module}) | single-service
407
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
408
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
396
409
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
397
410
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
398
411
  ```