@educa-corp/sdd-framework 0.2.1 → 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 (65) 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 +23 -10
  63. package/package.json +1 -1
  64. package/steps/context-loader.md +21 -8
  65. package/templates/project-context.yaml +23 -10
@@ -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
  ```
@@ -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
  ```
@@ -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
  ```
@@ -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
  ```
@@ -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
  ```
@@ -192,16 +192,28 @@ Nếu có section `services`:
192
192
  *(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`)*
193
193
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
194
194
 
195
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
196
- - 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.
197
- - 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.
195
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
196
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
197
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
198
+ - Nếu vẫn không xác định được → `active_platform = null`.
199
+
200
+ **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:
201
+
202
+ **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ũ:
198
203
  - Lưu `active_service` = `services.{domain}.path`
199
204
  - Lưu `active_service_module` = `services.{domain}.module`
200
205
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
201
206
 
202
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
203
- - Giữ path mặc định từ Bước 1
204
- - Đặt `active_service = unresolved`
207
+ **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):
208
+ - 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`).
209
+ - 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ể.
210
+ - 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}`".
211
+
212
+ *(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.)*
213
+
214
+ **3. Fallback**:
215
+ - 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`.
216
+ - 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).
205
217
 
206
218
  **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:`:
207
219
  - 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`.)*
@@ -221,7 +233,7 @@ Nếu có section `services`:
221
233
 
222
234
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
223
235
 
224
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
236
+ *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.*
225
237
 
226
238
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
227
239
 
@@ -397,7 +409,8 @@ Ticket : {ticket_prefix}-
397
409
  Dict : {loaded — N canonical terms, M banned terms | missing}
398
410
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
399
411
  Lessons : {loaded — N guardrails | chưa có}
400
- Service : {active_service} ({active_service_module}) | single-service
412
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
413
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
401
414
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
402
415
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
403
416
  ```
@@ -190,16 +190,28 @@ Nếu có section `services`:
190
190
  *(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`)*
191
191
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
192
192
 
193
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
194
- - 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.
195
- - 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.
193
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
194
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
195
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
196
+ - Nếu vẫn không xác định được → `active_platform = null`.
197
+
198
+ **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:
199
+
200
+ **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ũ:
196
201
  - Lưu `active_service` = `services.{domain}.path`
197
202
  - Lưu `active_service_module` = `services.{domain}.module`
198
203
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
199
204
 
200
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
201
- - Giữ path mặc định từ Bước 1
202
- - Đặt `active_service = unresolved`
205
+ **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):
206
+ - 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`).
207
+ - 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ể.
208
+ - 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}`".
209
+
210
+ *(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.)*
211
+
212
+ **3. Fallback**:
213
+ - 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`.
214
+ - 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).
203
215
 
204
216
  **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:`:
205
217
  - 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`.)*
@@ -219,7 +231,7 @@ Nếu có section `services`:
219
231
 
220
232
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
221
233
 
222
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
234
+ *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.*
223
235
 
224
236
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
225
237
 
@@ -395,7 +407,8 @@ Ticket : {ticket_prefix}-
395
407
  Dict : {loaded — N canonical terms, M banned terms | missing}
396
408
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
397
409
  Lessons : {loaded — N guardrails | chưa có}
398
- Service : {active_service} ({active_service_module}) | single-service
410
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
411
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
399
412
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
400
413
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
401
414
  ```
@@ -181,16 +181,28 @@ Nếu có section `services`:
181
181
  *(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`)*
182
182
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
183
183
 
184
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
185
- - 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.
186
- - 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.
184
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
185
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
186
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
187
+ - Nếu vẫn không xác định được → `active_platform = null`.
188
+
189
+ **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:
190
+
191
+ **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ũ:
187
192
  - Lưu `active_service` = `services.{domain}.path`
188
193
  - Lưu `active_service_module` = `services.{domain}.module`
189
194
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
190
195
 
191
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
192
- - Giữ path mặc định từ Bước 1
193
- - Đặt `active_service = unresolved`
196
+ **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):
197
+ - 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`).
198
+ - 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ể.
199
+ - 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}`".
200
+
201
+ *(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.)*
202
+
203
+ **3. Fallback**:
204
+ - 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`.
205
+ - 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).
194
206
 
195
207
  **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:`:
196
208
  - 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`.)*
@@ -210,7 +222,7 @@ Nếu có section `services`:
210
222
 
211
223
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
212
224
 
213
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
225
+ *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.*
214
226
 
215
227
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
216
228
 
@@ -386,7 +398,8 @@ Ticket : {ticket_prefix}-
386
398
  Dict : {loaded — N canonical terms, M banned terms | missing}
387
399
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
388
400
  Lessons : {loaded — N guardrails | chưa có}
389
- Service : {active_service} ({active_service_module}) | single-service
401
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
402
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
390
403
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
391
404
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
392
405
  ```
@@ -186,16 +186,28 @@ Nếu có section `services`:
186
186
  *(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`)*
187
187
  - Nếu `$ARGUMENTS` chứa một path, trích xuất segment domain sau `specs_dir`
188
188
 
189
- **2. Route tới service** nếu active domain khớp với một key trong `services`:
190
- - 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.
191
- - 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.
189
+ **1b. Phát hiện active platform** (chỉ cần khi service dạng map-theo-platform bước 2b):
190
+ - Đọc `@trace.platform` từ header của target `.feature` (`system` | `web` | `app`) Gate đã resolve target trước bước này.
191
+ - Nếu target không mang `@trace.platform` (vd targetPRD `.md`), thử suy từ segment `bdd/{platform}/` trong path target.
192
+ - Nếu vẫn không xác định được → `active_platform = null`.
193
+
194
+ **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:
195
+
196
+ **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ũ:
192
197
  - Lưu `active_service` = `services.{domain}.path`
193
198
  - Lưu `active_service_module` = `services.{domain}.module`
194
199
  - Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
195
200
 
196
- **3. Fallback** — nếu không phát hiện được domain hoặc không service key khớp:
197
- - Giữ path mặc định từ Bước 1
198
- - Đặt `active_service = unresolved`
201
+ **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):
202
+ - 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`).
203
+ - 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ể.
204
+ - 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}`".
205
+
206
+ *(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.)*
207
+
208
+ **3. Fallback**:
209
+ - 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`.
210
+ - 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).
199
211
 
200
212
  **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:`:
201
213
  - 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`.)*
@@ -215,7 +227,7 @@ Nếu có section `services`:
215
227
 
216
228
  ## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
217
229
 
218
- *Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc context ở chế độ single-service.*
230
+ *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.*
219
231
 
220
232
  Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
221
233
 
@@ -391,7 +403,8 @@ Ticket : {ticket_prefix}-
391
403
  Dict : {loaded — N canonical terms, M banned terms | missing}
392
404
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
393
405
  Lessons : {loaded — N guardrails | chưa có}
394
- Service : {active_service} ({active_service_module}) | single-service
406
+ Platform : {active_platform: system | web | app | — nếu chưa xác định}
407
+ Service : {active_service} ({active_service_module}) | multi (map-theo-platform, chốt khi target có platform) | single-service
395
408
  Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
396
409
  Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
397
410
  ```