@educa-corp/sdd-framework 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/build.js +9 -0
- package/bin/index.js +115 -4
- package/bin/self-check.js +354 -0
- package/bin/trace-schema.json +1199 -0
- package/commands/debug.md +19 -12
- package/commands/define-product.md +19 -12
- package/commands/dev-gen-test.md +53 -19
- package/commands/dev-run-test.md +55 -20
- package/commands/dev-run-test.tmpl +2 -1
- package/commands/dev-smoke-test.md +19 -12
- package/commands/extend-prd.md +907 -0
- package/commands/extend-prd.tmpl +270 -0
- package/commands/fix-bug.md +101 -15
- package/commands/fix-bug.tmpl +29 -3
- package/commands/generate-architecture.md +19 -12
- package/commands/generate-bdd.md +174 -48
- package/commands/generate-bdd.tmpl +107 -18
- package/commands/generate-code.md +122 -29
- package/commands/generate-code.tmpl +69 -10
- package/commands/generate-design-spec.md +19 -12
- package/commands/generate-prd.md +44 -12
- package/commands/generate-prd.tmpl +25 -0
- package/commands/generate-spec-manifest.md +19 -12
- package/commands/generate-tech-docs.md +22 -15
- package/commands/generate-tech-docs.tmpl +2 -2
- package/commands/learn.md +19 -12
- package/commands/map-testids.md +19 -12
- package/commands/propose-scenario.md +91 -15
- package/commands/propose-scenario.tmpl +72 -3
- package/commands/qc-analyze.md +19 -12
- package/commands/qc-design-test.md +20 -12
- package/commands/qc-design-test.tmpl +1 -0
- package/commands/qc-plan.md +19 -12
- package/commands/qc-report.md +19 -12
- package/commands/qc-review.md +19 -12
- package/commands/qc-run-test.md +88 -22
- package/commands/qc-run-test.tmpl +35 -3
- package/commands/refine-prd.md +19 -12
- package/commands/report-bug.md +19 -12
- package/commands/review-code.md +60 -14
- package/commands/review-code.tmpl +41 -2
- package/commands/review-context.md +62 -16
- package/commands/review-context.tmpl +43 -4
- package/commands/review-tech-docs.md +50 -14
- package/commands/review-tech-docs.tmpl +31 -2
- package/commands/setup-ai-first.md +26 -16
- package/commands/setup-ai-first.tmpl +7 -4
- package/commands/sync.md +43 -18
- package/commands/sync.tmpl +37 -14
- package/commands/update-framework.md +43 -4
- package/commands/update-framework.tmpl +37 -0
- package/commands/validate-traces.md +481 -49
- package/commands/validate-traces.tmpl +462 -37
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/README.md +56 -0
- package/core/commands/debug.md +19 -12
- package/core/commands/define-product.md +19 -12
- package/core/commands/dev-gen-test.md +53 -19
- package/core/commands/dev-run-test.md +55 -20
- package/core/commands/dev-smoke-test.md +19 -12
- package/core/commands/extend-prd.md +907 -0
- package/core/commands/fix-bug.md +101 -15
- package/core/commands/generate-architecture.md +19 -12
- package/core/commands/generate-bdd.md +174 -48
- package/core/commands/generate-code.md +122 -29
- package/core/commands/generate-design-spec.md +19 -12
- package/core/commands/generate-prd.md +44 -12
- package/core/commands/generate-spec-manifest.md +19 -12
- package/core/commands/generate-tech-docs.md +22 -15
- package/core/commands/learn.md +19 -12
- package/core/commands/map-testids.md +19 -12
- package/core/commands/propose-scenario.md +91 -15
- package/core/commands/qc-analyze.md +19 -12
- package/core/commands/qc-design-test.md +20 -12
- package/core/commands/qc-plan.md +19 -12
- package/core/commands/qc-report.md +19 -12
- package/core/commands/qc-review.md +19 -12
- package/core/commands/qc-run-test.md +88 -22
- package/core/commands/refine-prd.md +19 -12
- package/core/commands/report-bug.md +19 -12
- package/core/commands/review-code.md +60 -14
- package/core/commands/review-context.md +62 -16
- package/core/commands/review-tech-docs.md +50 -14
- package/core/commands/setup-ai-first.md +26 -16
- package/core/commands/sync.md +43 -18
- package/core/commands/update-framework.md +43 -4
- package/core/commands/validate-traces.md +481 -49
- package/core/modules/android-compose/stack-profile.yaml +1 -1
- package/core/modules/flutter/stack-profile.yaml +1 -1
- package/core/modules/ios-swiftui/stack-profile.yaml +1 -1
- package/core/modules/java-spring/stack-profile.yaml +1 -1
- package/core/modules/nextjs/stack-profile.yaml +1 -1
- package/core/modules/nuxt/stack-profile.yaml +1 -1
- package/core/modules/phaser-game/stack-profile.yaml +1 -1
- package/core/modules/php-laravel/stack-profile.yaml +1 -1
- package/core/modules/qc-playwright/stack-profile.yaml +1 -1
- package/core/modules/react/stack-profile.yaml +1 -1
- package/core/modules/react-native/stack-profile.yaml +1 -1
- package/core/modules/vue/stack-profile.yaml +1 -1
- package/core/rules/workflow.md +29 -0
- package/core/steps/gate.md +13 -8
- package/core/steps/report-footer.md +6 -4
- package/core/steps/trace-mirror.md +34 -7
- package/core/templates/README.md +47 -0
- package/core/templates/feature.template +14 -11
- package/core/templates/project-context.yaml +26 -14
- package/core/templates/tech-design.template.md +1 -1
- package/docs/01-getting-started/installation.md +18 -1
- package/docs/01-getting-started/what-is-sdd.md +4 -2
- package/docs/02-concepts/architecture.md +27 -3
- package/docs/02-concepts/pipeline-steps/02-specification.md +39 -3
- package/docs/02-concepts/pipeline-steps/04-bdd.md +24 -2
- package/docs/02-concepts/pipeline-steps/05-tech-docs.md +18 -1
- package/docs/02-concepts/pipeline-steps/06-code.md +35 -4
- package/docs/02-concepts/pipeline-steps/09-validate-traces.md +137 -12
- package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +59 -3
- package/docs/02-concepts/roles-and-hitl.md +1 -1
- package/docs/02-concepts/traceability.md +126 -94
- package/docs/03-guides/developer.md +20 -4
- package/docs/03-guides/product-owner.md +72 -68
- package/docs/03-guides/tester-qa.md +81 -70
- package/docs/04-reference/commands.md +134 -105
- package/docs/04-reference/configuration.md +146 -94
- package/docs/04-reference/trace-schema.md +145 -37
- package/docs/explain/02-generate-prd.md +80 -78
- package/docs/explain/02b-extend-prd.md +125 -0
- package/docs/explain/03-refine-prd.md +86 -86
- package/docs/explain/04-review-context.md +18 -1
- package/docs/explain/06-generate-bdd.md +23 -0
- package/docs/explain/08-review-tech-docs.md +20 -5
- package/docs/explain/10-review-code.md +36 -2
- package/docs/explain/19-qc-run-test.md +87 -67
- package/docs/explain/21-validate-traces.md +74 -68
- package/docs/explain/23-fix-bug.md +19 -3
- package/docs/explain/26-propose-scenario.md +70 -63
- package/docs/explain/README.md +135 -134
- package/modules/android-compose/stack-profile.yaml +1 -1
- package/modules/flutter/stack-profile.yaml +1 -1
- package/modules/ios-swiftui/stack-profile.yaml +1 -1
- package/modules/java-spring/stack-profile.yaml +1 -1
- package/modules/nextjs/stack-profile.yaml +1 -1
- package/modules/nuxt/stack-profile.yaml +1 -1
- package/modules/phaser-game/stack-profile.yaml +1 -1
- package/modules/php-laravel/stack-profile.yaml +1 -1
- package/modules/qc-playwright/stack-profile.yaml +1 -1
- package/modules/react/stack-profile.yaml +1 -1
- package/modules/react-native/stack-profile.yaml +1 -1
- package/modules/vue/stack-profile.yaml +1 -1
- package/package.json +5 -4
- package/rules/workflow.md +29 -0
- package/scripts/migrate-bdd-platform.js +286 -0
- package/steps/gate.md +13 -8
- package/steps/report-footer.md +6 -4
- package/steps/trace-mirror.md +34 -7
- package/templates/README.md +47 -0
- package/templates/feature.template +14 -11
- package/templates/project-context.yaml +26 -14
- package/templates/tech-design.template.md +1 -1
|
@@ -7,7 +7,16 @@
|
|
|
7
7
|
{{include:steps/context-loader.md}}
|
|
8
8
|
|
|
9
9
|
> **Proposal của tester (input tuỳ chọn):** trước khi sinh, quét `{paths.bdd_proposals_dir}/` (mặc định `{spec_source}/feedback/bdd-proposals/`) tìm `{UC-ID}-*.md`. Với mỗi proposal:
|
|
10
|
-
> - `Status: accepted` (PO/Dev đã duyệt) → chèn scenario vào `.feature` của UC (
|
|
10
|
+
> - `Status: accepted` (PO/Dev đã duyệt) → chèn scenario vào `.feature` của UC, **normalize khi chèn** (xem dưới), rồi **lưu trữ**: chuyển file sang `{paths.bdd_proposals_dir}/archived/` + đặt `Status: incorporated`, và **commit + push** spec repo để gỡ khỏi feedback chung.
|
|
11
|
+
>
|
|
12
|
+
> **Normalize — bắt buộc, nếu không scenario sẽ vô hình với trace:**
|
|
13
|
+
> 1. Gán `# @trace.scenario: {UC-ID}-SC{N}` với `{N}` = số SC **kế tiếp** trong file đó (thay placeholder `SC?`).
|
|
14
|
+
> 2. Giữ `# @trace.sc_version: 1.0`. Bổ sung `# @trace.business_rules` nếu proposal để `—` (suy từ AC mà dòng `# Covers:` trỏ tới); không suy được → để `—` và nêu trong report.
|
|
15
|
+
> 3. **Strip** tag `@proposed` / `@from-test` — chúng là nhãn vòng đời proposal, không thuộc BDD canonical.
|
|
16
|
+
> 4. Đặt scenario vào **đúng NHÓM** theo business theme (C.5), không nối vào cuối file.
|
|
17
|
+
> 5. **Append row TSV** cho SC mới (như nhánh "SC mới" ở Write Trace State: `spec_ver = 1.0`, mọi cột gen/test/qc = `—`, `status = UNTRACKED`).
|
|
18
|
+
>
|
|
19
|
+
> **Backward-compat:** proposal cũ mang `@trace.uc=` / `@trace.ac=` (vocabulary trước đây, không thuộc contract `.feature`) → tự map sang canonical (`@trace.uc` bỏ — số UC đã có trong `sc_id`; `@trace.ac` → dòng `# Covers:`) và in một dòng cảnh báo khuyến nghị proposal sau viết theo format mới.
|
|
11
20
|
> - `Status: proposed`/`rejected` (hoặc thiếu `Status`) → **bỏ qua**, để nguyên cho PO/Dev xử lý (KHÔNG tự đoán, KHÔNG tự đưa vào).
|
|
12
21
|
> Bỏ qua sạch nếu folder rỗng.
|
|
13
22
|
|
|
@@ -213,9 +222,24 @@ Chỉ cần kiểm tra trạng thái đã phân giải:
|
|
|
213
222
|
| `active_service = "unresolved"` (có section `services` nhưng domain PRD không khớp entry nào) | **DỪNG**, báo: "Domain `{domain}` của PRD không khớp service nào trong `services:` của project-context.yaml — bổ sung mapping rồi chạy lại." (Không đoán/hỏi tay — domain là khoá định danh, lệch là lỗi cấu hình cần sửa ở SoT.) |
|
|
214
223
|
| Single-service (không có section `services`) | `active_module = tech_stack.module` (đã set ở Bước 6.5). Tiếp tục. |
|
|
215
224
|
|
|
216
|
-
|
|
225
|
+
### Phân giải `active_platform` (umbrella mode)
|
|
217
226
|
|
|
218
|
-
|
|
227
|
+
Umbrella mode không hỏi platform (khác spec repo mode) — nó **suy** từ module của service. Bắt buộc phải có giá trị: `active_platform` đi vào **path file**, vào **header `@trace.platform`**, và vào **tên sổ trace** `{UC-ID}-{platform}.tsv`.
|
|
228
|
+
|
|
229
|
+
| `active_module` | → `active_platform` |
|
|
230
|
+
|---|---|
|
|
231
|
+
| react · nextjs · vue · nuxt · angular | `web` |
|
|
232
|
+
| flutter · react-native · ios-swiftui · android-compose | `app` |
|
|
233
|
+
| java-spring · golang · dotnet · php-laravel | `system` |
|
|
234
|
+
| context-engineering · phaser-game | theo `platform_type` của stack-profile (`backend` → `system`, còn lại → `web`) |
|
|
235
|
+
|
|
236
|
+
- `active_service = "multi"` + `service_candidates_kind = platform` → **nhiều** `active_platform` (một cho mỗi platform trong `service_candidates`); sinh một file `.feature` cho mỗi platform, module lấy theo `service_candidates.{platform}.module`.
|
|
237
|
+
- Không suy được (module lạ, không có trong bảng và không có `platform_type`) → **DỪNG**, hỏi người dùng chọn `web`/`app`/`system`. **KHÔNG** ghi file khi chưa có `active_platform` — file thiếu platform sẽ vô hình với `/validate-traces` và va chạm tên với platform khác.
|
|
238
|
+
|
|
239
|
+
**Output path (umbrella mode):** `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC{N}-{slug}.feature`
|
|
240
|
+
|
|
241
|
+
*(**Subfolder `{platform}/` LUÔN có — mọi mode.** `web` và `system` của cùng một UC là hai file khác nhau: nếu bỏ subfolder, chúng ra cùng filename và **ghi đè nhau**; ngoài ra trace tách theo platform (`{UC-ID}-{platform}.tsv`) nên bố cục spec phải tách tương ứng.*
|
|
242
|
+
*Cái KHÔNG thêm là subfolder theo **service**: feature-package đã domain-scoped sẵn ở `{domain}/`, mà service route 1-1 theo domain — thêm subfolder service chỉ lặp lại domain. `active_service` chỉ dùng cho `service_root`/từ vựng, KHÔNG vào path spec.)*
|
|
219
243
|
|
|
220
244
|
**Từ vựng theo platform** — điều chỉnh cách viết step BDD theo `active_module`:
|
|
221
245
|
|
|
@@ -298,9 +322,9 @@ Sau khi sinh tất cả file `.feature` và `.tsv` cho UC được giao, trả v
|
|
|
298
322
|
|
|
299
323
|
Trước khi sinh, kiểm tra các file `.feature` có sẵn cho PRD này:
|
|
300
324
|
|
|
301
|
-
1.
|
|
302
|
-
|
|
303
|
-
|
|
325
|
+
1. Search path (**giống nhau ở cả hai mode** — bố cục `bdd/{platform}/` là chuẩn duy nhất):
|
|
326
|
+
`{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC*.feature`
|
|
327
|
+
> **Legacy:** nếu không khớp gì, thử thêm một lần ở bố cục phẳng cũ `…/bdd/{TICKET-ID}-UC*.feature`. Khớp → xử lý như file có sẵn **và** in cảnh báo: `⚠️ File .feature đang ở bố cục phẳng (trước v0.4.1). Chạy: npx sdd-framework --migrate-bdd-platform để chuyển sang bdd/{platform}/.` Đừng tự di chuyển file trong lệnh này.
|
|
304
328
|
2. Đọc `| **Version** |` hiện tại của PRD từ metadata (vd: `1.2`).
|
|
305
329
|
|
|
306
330
|
**Nếu không có file feature nào** → gen mới, tiếp tục bình thường. Dùng version PRD làm `@trace.prd_version`.
|
|
@@ -349,7 +373,7 @@ Trước khi sinh, kiểm tra các file `.feature` có sẵn cho PRD này:
|
|
|
349
373
|
| Check | Rule |
|
|
350
374
|
|-------|------|
|
|
351
375
|
| C.1 Wireframe Coverage | Mỗi component/action trong Wireframe (PRD §4b) có ≥1 SC. **FE/App: mỗi Screen State (≠default) và mỗi AC-UI behavioral của design-spec (`design_coverage`) cũng phải có ≥1 SC** — dedup với AC nghiệp vụ PRD; bỏ AC-UI visual thuần. |
|
|
352
|
-
| C.2 PRD Traceability | Mỗi AC và mỗi BR
|
|
376
|
+
| C.2 PRD Traceability | Mỗi AC **thuộc UC này** (đúng tập ở `**AC liên quan:**` của UC trong PRD §3) và mỗi BR trong bảng Business Rule của UC này map tới ≥1 SC. **KHÔNG** phủ AC của UC khác — đó là việc của `.feature` UC đó. *(AC ở PRD là global cấp PRD, còn `.feature` là per-UC; enforce theo nghĩa "mọi AC của PRD" sẽ bắt AI bịa scenario ngoài scope hoặc báo MISSING giả.)* |
|
|
353
377
|
| C.3 Business Dictionary | Dùng đúng canonical term từ business-dictionary.md. |
|
|
354
378
|
| C.4 Banned Terms | 0 banned term trong file — grep trước khi gen. |
|
|
355
379
|
| C.5 NHÓM Grouping | Feature ≥3 SC → PHẢI có NHÓM grouping theo business theme. |
|
|
@@ -405,17 +429,49 @@ CHECKPOINT: "Outline này đúng chưa? Bạn muốn thêm hay bớt SC nào kh
|
|
|
405
429
|
|
|
406
430
|
## Generate
|
|
407
431
|
|
|
408
|
-
**Output path
|
|
409
|
-
- **Spec repo mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC{N}-{slug}.feature`
|
|
410
|
-
- **Umbrella mode**: `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC{N}-{slug}.feature` *(service route 1-1 theo domain → không thêm subfolder service)*
|
|
432
|
+
**Output path — MỘT bố cục duy nhất cho cả hai mode:**
|
|
411
433
|
|
|
412
|
-
|
|
434
|
+
```
|
|
435
|
+
{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC{N}-{slug}.feature
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
`{active_platform}` ∈ `web` | `app` | `system` — từ Platform Selection (spec repo mode) hoặc suy từ `active_module` (umbrella mode, xem §Service Detection). **Không có `active_platform` thì không ghi file.**
|
|
439
|
+
|
|
440
|
+
Với mỗi UC, ghi vào path trên và set `# @trace.platform: {active_platform}` trong header (**bắt buộc, mọi mode** — `/generate-code` dùng nó để quyết BE/FE và để định vị sổ trace; `/generate-tech-docs` và `context-loader` cũng đọc nó). Dùng từ vựng cho active platform.
|
|
413
441
|
|
|
414
442
|
```gherkin
|
|
415
443
|
{{include:templates/feature.template}}
|
|
416
444
|
```
|
|
417
445
|
|
|
418
|
-
|
|
446
|
+
> **Template này đến từ đâu — đọc trước khi định "customize":**
|
|
447
|
+
> Skeleton trên là **single-source** ở `templates/feature.template` **của repo framework**, được `{{include}}` **nướng cứng vào lệnh này lúc `npm run build`**. Muốn đổi cấu trúc mọi `.feature` sinh ra: sửa file đó **trong repo framework** rồi build lại + phát hành.
|
|
448
|
+
>
|
|
449
|
+
> **Sửa `.agent/templates/feature.template` trong project KHÔNG có tác dụng** — không lệnh nào đọc file đó; nó chỉ là bản tham khảo. Và nó **sẽ bị ghi đè im lặng** ở lần `/update-framework` kế tiếp (`--init` copy `core/` → `.agent/` vô điều kiện; file duy nhất được giữ là `.agent/project-context.yaml`).
|
|
450
|
+
>
|
|
451
|
+
> Coverage Matrix + Pre-merge Checklist nằm ở **cuối** template, thêm vào cuối mỗi file.
|
|
452
|
+
|
|
453
|
+
### Bump `@trace.sc_version` *(CHỈ khi gen lại — file `.feature` đã tồn tại)*
|
|
454
|
+
|
|
455
|
+
*Bỏ qua hoàn toàn khi gen mới: mọi SC nhận `1.0`.*
|
|
456
|
+
|
|
457
|
+
`@trace.sc_version` là version **của từng scenario** — nó là tín hiệu DUY NHẤT cho `/validate-traces` biết code của SC đó đã lỗi thời (`spec_ver != gen_ver` → `DRIFT`). Không bump = code sinh từ scenario cũ mãi mãi hiện `OK`. Phân biệt với `@trace.bdd_version` (version **cả file**, không đủ phân giải để biết SC nào cần regen).
|
|
458
|
+
|
|
459
|
+
Trước khi ghi file, với **mỗi** SC, so **thân scenario** bản mới vs bản trên disk theo 4 thành phần:
|
|
460
|
+
|
|
461
|
+
1. dòng `Scenario:` (tên)
|
|
462
|
+
2. chuỗi step `Given` / `When` / `Then` / `And` (nội dung + thứ tự)
|
|
463
|
+
3. nội dung data table (nếu có)
|
|
464
|
+
4. dòng `# Side-effects:`
|
|
465
|
+
|
|
466
|
+
| Kết quả so | Hành động |
|
|
467
|
+
|---|---|
|
|
468
|
+
| Khác ở **bất kỳ** thành phần nào | `@trace.sc_version` += `0.1` (vd `1.0` → `1.1`) |
|
|
469
|
+
| Giống hoàn toàn | **GIỮ NGUYÊN** — bump vô cớ sẽ tạo `DRIFT` giả, làm cờ mất giá trị |
|
|
470
|
+
| SC mới (chưa có trong bản cũ) | `1.0` |
|
|
471
|
+
|
|
472
|
+
*(Thay đổi ngoài 4 thành phần trên — `@trace.business_rules`, tag `@happy`/`@edge`, comment — KHÔNG bump: chúng không đổi hành vi mà code phải implement.)*
|
|
473
|
+
|
|
474
|
+
In danh sách SC được bump vào report cuối để người dùng biết cái nào sẽ hiện `DRIFT`.
|
|
419
475
|
|
|
420
476
|
---
|
|
421
477
|
|
|
@@ -427,16 +483,33 @@ Sau khi sinh tất cả file `.feature`, tạo hoặc cập nhật **sổ trace
|
|
|
427
483
|
|
|
428
484
|
**Cột TSV (tab-separated, một header row + một data row cho mỗi scenario):**
|
|
429
485
|
```
|
|
430
|
-
sc_id\tsc_title\tspec_ver\tgen_ver\timplemented_by\ttest_count\ttest_classes\tdev_selftest\tdev_selftest_at\tqc_status\tqc_run_at\tqc_owner\tqc_blocked_by\tprd_version\tbdd_version\ttech_doc_revision\tfe_tech_doc_revision\tprd_status\tuc_status\tfe_phase\tstatus\tlast_updated
|
|
486
|
+
sc_id\tsc_title\tspec_ver\tgen_ver\timplemented_by\ttest_count\ttest_classes\tdev_selftest\tdev_selftest_at\tqc_status\tqc_run_at\tqc_owner\tqc_blocked_by\tprd_version\tbdd_version\ttech_doc_revision\tfe_tech_doc_revision\tprd_status\tuc_status\tfe_phase\tstatus\tlast_updated\tservice\tdesign_spec_version
|
|
431
487
|
```
|
|
432
488
|
|
|
433
489
|
**Rules:**
|
|
434
490
|
- Nếu file chưa tồn tại → tạo với header row + tất cả scenario row.
|
|
435
491
|
- Nếu file tồn tại (gen lại) → với mỗi SC trong `.feature` mới:
|
|
436
|
-
- SC đã có trong `.tsv` VÀ `spec_ver` không đổi → chỉ cập nhật: `sc_title`, `prd_version`, `bdd_version`, `prd_status`, `uc_status`, `last_updated`. Giữ nguyên các cột khác.
|
|
437
|
-
- SC đã có trong `.tsv` VÀ `spec_ver` đổi (scenario bị sửa) → cập nhật: `sc_title`, `spec_ver`, `prd_version`, `bdd_version`, `prd_status`, `uc_status`, `last_updated` VÀ set `status = DRIFT` ngay (để TSV phản ánh drift mà không cần đợi `/validate-traces`). Giữ nguyên `gen_ver`, `implemented_by`, `test_count`, `test_classes`, `tech_doc_revision`, `fe_tech_doc_revision`.
|
|
492
|
+
- SC đã có trong `.tsv` VÀ `spec_ver` không đổi → chỉ cập nhật: `sc_title`, `prd_version`, `bdd_version`, `prd_status`, `uc_status`, `service`, `design_spec_version`, `last_updated`. Giữ nguyên các cột khác. *(`service` + `design_spec_version` là sự thật cấp-file, làm mới theo `.feature`/design-spec hiện tại — chúng KHÔNG phải tín hiệu nghiệm thu nên làm mới chúng không che giấu gì.)*
|
|
493
|
+
- SC đã có trong `.tsv` VÀ `spec_ver` đổi (scenario bị sửa) → cập nhật: `sc_title`, `spec_ver`, `prd_version`, `bdd_version`, `prd_status`, `uc_status`, `service`, `design_spec_version`, `last_updated` VÀ set `status = DRIFT` ngay (để TSV phản ánh drift mà không cần đợi `/validate-traces`). Giữ nguyên `gen_ver`, `implemented_by`, `test_count`, `test_classes`, `tech_doc_revision`, `fe_tech_doc_revision`.
|
|
494
|
+
**VÀ hạ hiệu lực tín hiệu kiểm thử của đúng SC đó** — spec vừa đổi nên test/QC cũ đang nghiệm thu một hành vi **không còn tồn tại**:
|
|
495
|
+
`dev_selftest → not_run` · `dev_selftest_at → —` · `qc_status → not_run` · `qc_run_at → —`.
|
|
496
|
+
> **Vì sao bắt buộc** *(luật "Làm mất hiệu lực ≠ ghi đè", `rules/workflow.md`)*: không hạ thì chuỗi sau báo xanh sai — spec đổi → `DRIFT` → `/generate-code` sửa method → `gen_ver = spec_ver` → `/validate-traces` Rule 4 cho `OK` (vì `test_count` vẫn > 0) → dashboard hiện `OK · ✅ 10 tests · qc pass` trong khi hành vi mới **chưa được test lần nào**. Đây là lớp lỗi nguy hiểm hơn G1: G1 làm cờ im lặng, cái này làm cờ **nói dối**.
|
|
497
|
+
> **KHÔNG** đụng `test_count`/`test_classes` (test vẫn nằm trên đĩa — số lượng không sai, chỉ nội dung cũ; hạ số sẽ làm tỷ lệ coverage nhảy loạn) và **KHÔNG** đụng `qc_owner`/`qc_blocked_by` (con trỏ tới bug — spec đổi không làm bug biến mất).
|
|
498
|
+
In cảnh báo kèm: `⚠️ {test_count} test của {sc_id} viết cho spec cũ — /dev-gen-test rà lại trước khi chạy`.
|
|
438
499
|
- SC mới (thêm trong lần gen lại này) → append row mới với `gen_ver`, `implemented_by`, `test_count`, `test_classes`, `dev_selftest`, `dev_selftest_at`, `qc_status`, `qc_run_at`, `qc_owner`, `qc_blocked_by`, `tech_doc_revision`, `fe_tech_doc_revision` đều set `—`.
|
|
439
|
-
- SC không còn trong `.feature` (bị xoá
|
|
500
|
+
- SC không còn trong `.feature` (bị xoá / gộp / đổi số) → **phụ thuộc SC đó đã có code chưa:**
|
|
501
|
+
- `implemented_by == —` (**chưa** có code) → **xoá row**. Không có gì mồ côi.
|
|
502
|
+
- `implemented_by != —` (**ĐÃ** có code) → **GIỮ row**, set `status = ORPHANED`, giữ nguyên `implemented_by` / `test_count` / `test_classes` / các cột qc, cập nhật `last_updated`. **KHÔNG xoá** — xoá row thì method đó thành vô hình: không `UNTRACKED`, không `GAP`, không `DRIFT`, không xuất hiện ở report nào, mà vẫn nằm trong code và vẫn được caller gọi. Coverage còn *đẹp hơn* thực tế vì mẫu số nhỏ đi.
|
|
503
|
+
In cảnh báo nổi bật ở report cuối:
|
|
504
|
+
```
|
|
505
|
+
⚠️ ORPHANED — {UC-ID}-SC{N} "{sc_title}" đã bị xoá khỏi .feature nhưng còn code:
|
|
506
|
+
{implemented_by} (+ {test_count} test: {test_classes})
|
|
507
|
+
Không tự hết — chọn MỘT:
|
|
508
|
+
(a) behavior không còn cần → xoá method + test, rồi xoá row khỏi .tsv
|
|
509
|
+
(b) SC bị xoá do nhầm → đưa scenario trở lại .feature (row về DRIFT/OK bình thường)
|
|
510
|
+
(/validate-traces giữ cờ ORPHANED 🔴 và chặn "pass" tới khi xử lý xong.)
|
|
511
|
+
```
|
|
512
|
+
*(An toàn: sổ này chỉ chứa scenario của `{active_platform}`, so với `.feature` của chính platform đó — không bao giờ đụng scenario platform khác.)*
|
|
440
513
|
|
|
441
514
|
**Giá trị ghi cho mỗi scenario:**
|
|
442
515
|
|
|
@@ -464,6 +537,8 @@ sc_id\tsc_title\tspec_ver\tgen_ver\timplemented_by\ttest_count\ttest_classes\tde
|
|
|
464
537
|
| `fe_phase` | `—` (set bởi `/generate-code --phase` khi FE implement) |
|
|
465
538
|
| `status` | `UNTRACKED` |
|
|
466
539
|
| `last_updated` | hôm nay `YYYY-MM-DD` |
|
|
540
|
+
| `service` | `@trace.service` từ header `.feature` — đội/submodule sở hữu scenario này. `multi` nếu chưa chốt (map-theo-platform ở cấp PRD), `unresolved` nếu domain không khớp entry nào, `—` ở single-service mode. **Đừng bỏ trống** — trace gộp không tách theo service nên đây là chỗ DUY NHẤT mang thông tin sở hữu ở cấp row. |
|
|
541
|
+
| `design_spec_version` | `\| **Version** \|` của design-spec đã nạp ở §Design Spec — Gate & Load. `—` cho `system`/backend (không có design-spec), và `—` khi người dùng chọn "Y — vẫn sinh BDD" mà không có design-spec. |
|
|
467
542
|
|
|
468
543
|
## Refresh Panel Mirror
|
|
469
544
|
{{include:steps/trace-mirror.md}}
|
|
@@ -487,9 +562,9 @@ Next (spec repo):
|
|
|
487
562
|
→ Sau khi gen hết platform: commit + push + báo team dev
|
|
488
563
|
→ Team dev đọc BDD từ spec submodule — không chạy /generate-bdd ở phía họ
|
|
489
564
|
|
|
490
|
-
[Umbrella mode — service: {active_service}]
|
|
565
|
+
[Umbrella mode — service: {active_service} · platform: {active_platform} (suy từ module {active_module})]
|
|
491
566
|
Files:
|
|
492
|
-
{paths.specs_dir}/{domain}/{prd-slug}/bdd/{TICKET-ID}-UC1-{slug}.feature ({N} scenarios)
|
|
567
|
+
{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/{TICKET-ID}-UC1-{slug}.feature ({N} scenarios)
|
|
493
568
|
Trace:
|
|
494
569
|
{paths.trace_dir}/{domain}/{prd-slug}/{TICKET-ID}-UC1-{active_platform}.tsv ({N} rows)
|
|
495
570
|
Next (umbrella):
|
|
@@ -497,5 +572,19 @@ Next (umbrella):
|
|
|
497
572
|
→ /generate-tech-docs {feature-file}
|
|
498
573
|
→ /generate-code {feature-file}
|
|
499
574
|
|
|
575
|
+
{chỉ khi gen lại VÀ có ≥1 SC bị bump — ngược lại bỏ cả khối}
|
|
576
|
+
🔄 sc_version đã bump (scenario đổi nội dung → code cũ lỗi thời):
|
|
577
|
+
{UC-ID}-SC2 1.0 → 1.1 {sc_title}
|
|
578
|
+
{UC-ID}-SC5 1.2 → 1.3 {sc_title}
|
|
579
|
+
→ {n} SC này sẽ hiện DRIFT ở /validate-traces. Sinh lại code: /generate-code {feature-file}
|
|
580
|
+
|
|
581
|
+
{cùng điều kiện — chỉ in các SC bump mà TRƯỚC ĐÓ có dev_selftest/qc_status khác "—"}
|
|
582
|
+
🔻 Tín hiệu kiểm thử bị hạ (spec vừa đổi — nghiệm thu cũ hết hiệu lực):
|
|
583
|
+
{UC-ID}-SC2 dev_selftest pass→not_run · qc_status pass→not_run
|
|
584
|
+
⚠️ {n} test của các SC này viết cho spec CŨ — rà lại nội dung, đừng chỉ chạy lại.
|
|
585
|
+
→ sau khi /generate-code: /dev-gen-test (rà test) → /dev-run-test → QC /qc-run-test
|
|
586
|
+
ℹ️ Coverage "đã kiểm đạt" sẽ TỤT trên dashboard — đó là số đúng; số cũ mới là số sai.
|
|
587
|
+
(Tỷ lệ phủ code/test KHÔNG đổi — test_count giữ nguyên vì test vẫn nằm trên đĩa.)
|
|
588
|
+
|
|
500
589
|
📊 Living Docs: chạy /validate-traces (hoặc /sync) để push trace này lên dashboard spec-module.
|
|
501
590
|
```
|
|
@@ -32,23 +32,23 @@ Hiển thị và chờ phản hồi:
|
|
|
32
32
|
```
|
|
33
33
|
⚙️ MODEL CHECK
|
|
34
34
|
──────────────────────────────────────────────────────────────────
|
|
35
|
-
Recommended :
|
|
35
|
+
Recommended : model Opus mới nhất
|
|
36
36
|
Why needed : Phân tích spec, review kiến trúc, sinh code đòi hỏi
|
|
37
|
-
suy luận sâu. Model nhỏ hơn dễ bỏ sót edge case.
|
|
37
|
+
suy luận sâu. Model nhỏ hơn (Haiku/Sonnet) dễ bỏ sót edge case.
|
|
38
38
|
|
|
39
39
|
Cách đổi trong Claude Code:
|
|
40
|
-
•
|
|
41
|
-
• hoặc:
|
|
40
|
+
• /model → chọn model Opus
|
|
41
|
+
• hoặc: Settings → Model
|
|
42
42
|
|
|
43
|
-
Đang chạy
|
|
44
|
-
Y — đúng
|
|
43
|
+
Đang chạy một model Opus?
|
|
44
|
+
Y — đúng → tiếp tục
|
|
45
45
|
S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
|
|
46
46
|
──────────────────────────────────────────────────────────────────
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
- "Y" → tiếp tục sang Bước 1.
|
|
50
50
|
- "S" → tiếp tục sang Bước 1 (người dùng chấp nhận rủi ro, thêm ⚠️ vào report cuối).
|
|
51
|
-
- "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang
|
|
51
|
+
- "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang một model Opus (`/model`) rồi chạy lại lệnh này."
|
|
52
52
|
|
|
53
53
|
## Bước 1 — Xác định Target File
|
|
54
54
|
|
|
@@ -57,7 +57,12 @@ Hiển thị và chờ phản hồi:
|
|
|
57
57
|
2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
|
|
58
58
|
- **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
|
|
59
59
|
- **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
|
|
60
|
-
- **Lệnh tech-docs
|
|
60
|
+
- **Lệnh tech-docs** — target là tech-doc **gộp cấp PRD** `{TICKET-ID}-tech-design.md` (MỘT doc phủ nhiều UC; danh sách UC nằm ở `@trace.ucs`). Vì tên file mang `{TICKET-ID}` chứ **không** mang `{UC-ID}`, phải tách trước khi glob:
|
|
61
|
+
- `$ARGUMENTS` là **UC-ID** (`{TICKET-ID}-UC{N}`) → lấy `{TICKET-ID}` = phần **trước** `-UC`, rồi glob `{specs_dir}/{domain}/*/tech-docs/{TICKET-ID}-tech-design.md`.
|
|
62
|
+
- `$ARGUMENTS` là **TICKET-ID** → glob trực tiếp như trên.
|
|
63
|
+
- Chưa biết domain → `{specs_dir}/*/*/tech-docs/{TICKET-ID}-tech-design.md`.
|
|
64
|
+
- Vẫn không khớp → glob rộng `{specs_dir}/*/*/tech-docs/*tech-design*.md` rồi liệt kê để người dùng chọn.
|
|
65
|
+
*(Đừng glob `{UC-ID}*-tech-design*.md` — nó nở thành `FT-001-UC1*-tech-design*.md` và **không bao giờ** khớp `FT-001-tech-design.md`.)*
|
|
61
66
|
- **Lệnh design-spec**: `{specs_dir}/{domain}/*/design-spec/{TICKET-ID}*.md`.
|
|
62
67
|
|
|
63
68
|
Khi một file khớp: đặt nó làm target **và** ghi lại `domain` + `prd_slug` từ path của nó (theo quy tắc trích xuất trong `context-loader.md` Bước 1 — `prd_slug` = segment đầu tiên sau `{specs_dir}/{domain}/`). Mọi path mà lệnh đọc/ghi về sau (BDD/tech-docs/design-spec/trace cùng cấp) đều dùng **`prd_slug` đã phân giải đó**, nên tất cả artifact nằm chung một feature package. Nếu nhiều file khớp (vd: nhiều platform), chọn theo platform/scope của lệnh hoặc liệt kê ra và hỏi.
|
|
@@ -537,6 +542,14 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
|
|
|
537
542
|
```
|
|
538
543
|
Chỉ tiếp khi Y. *(Khác FE: FE degrade êm để prototype qua mock; BE thì contract là sản phẩm chính → chặn mềm.)*
|
|
539
544
|
- **Có §4 nhưng `@trace.status = draft/in-review`, HOẶC §12 GAP Register còn 🔴 blocker `open` chạm UC này** → WARN (không chặn): "contract chưa chốt / còn {n} blocker-GAP open — có thể phải rework khi contract đổi."
|
|
545
|
+
- **Tech-doc lỗi thời so với BDD** — so entry `{@trace.platform}` trong map `@trace.bdd_versions` của tech-doc vs `@trace.bdd_version` của `.feature` target. Tech-doc **cũ hơn** → WARN (không chặn), kể cả khi `@trace.status: approved`:
|
|
546
|
+
```
|
|
547
|
+
⚠️ §4 contract dựng từ BDD v{old}, .feature này giờ v{new}.
|
|
548
|
+
Doc vẫn 'approved' nên shape dưới đây được lấy nguyên văn — nhưng nó phản ánh
|
|
549
|
+
behavior CŨ. Nếu BDD đổi request/response/error thì code sinh ra sẽ sai từ nguồn.
|
|
550
|
+
Khuyến nghị: /generate-tech-docs {feature-file} → /review-tech-docs (cổng T3b) trước.
|
|
551
|
+
```
|
|
552
|
+
*(Chỉ WARN chứ không chặn: BDD hay bump vì lý do không chạm contract — sửa từ ngữ step, thêm side-effect assertion. Người đọc warning là người biết. `/validate-traces` giữ cờ `TECHDOC_STALE_VS_BDD` song song.)*
|
|
540
553
|
- **Có §4 + `@trace.status: approved` + 0 blocker-GAP** → dùng §4 làm nguồn contract (shape DTO/endpoint/error lấy nguyên văn từ đây, KHÔNG tự chế).
|
|
541
554
|
|
|
542
555
|
---
|
|
@@ -545,14 +558,21 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
|
|
|
545
558
|
|
|
546
559
|
> **Nguồn chuẩn quyết BE/FE = `@trace.platform` của FILE FEATURE** (`system` → BE · `web`/`app` → FE). KHÔNG dùng `platform_type` (suy từ module) để quyết BE/FE — nó chỉ dùng cho **idiom stack/module** (cú pháp, layer, thư viện). Lý do: repo fullstack một-module (vd Next.js có API route) có `platform_type` cố định một giá trị, nhưng vẫn có cả feature `system` (BE) lẫn `web` (FE) — chỉ tag của chính feature mới đúng.
|
|
547
560
|
|
|
548
|
-
Parse `$ARGUMENTS` tìm flag `--phase`:
|
|
561
|
+
Parse `$ARGUMENTS` tìm flag `--phase` và `--force`:
|
|
549
562
|
|
|
550
563
|
| Flag | Ý nghĩa |
|
|
551
564
|
|---|---|
|
|
552
565
|
| `--phase=ui` | FE Phase 1 — sinh UI + layer mock API từ System BDD contract |
|
|
553
566
|
| `--phase=integration` | FE Phase 2 — thay mock adapter bằng lời gọi API thật từ tech docs |
|
|
567
|
+
| `--force` | "Gen lại tường minh" — **CHỈ** bỏ qua guard status ở §Read Trace State (không skip row đang `OK`). Xem định nghĩa hẹp bên dưới. |
|
|
554
568
|
| *(không có)* | Default — full: **BE/`system`** → full backend; **FE (`web`/`app`)** → **FE full** (sinh UI + wire API thật trong một lần, không qua bước mock) |
|
|
555
569
|
|
|
570
|
+
> **`--force` có phạm vi HẸP — đây là ranh giới cứng, không phải khuyến nghị.**
|
|
571
|
+
> Nó bỏ qua **đúng một** thứ: luật "row `OK` thì skip" ở §Read Trace State. **Mọi guard khác giữ nguyên hiệu lực:** Scope Lock (cấm implement scenario của `.feature` khác) · quy tắc EXTEND phi-phá-huỷ (đọc lại trước khi ghi · CẤM full Write trên file đã tồn tại · output phải là superset chặt) · Guard sau-ghi · Fill-before-create · Build Verify.
|
|
572
|
+
> `--force` **KHÔNG** phải "ghi đè tất cả". Không có cờ nào trong lệnh này cho phép điều đó — mất member/tag của UC khác luôn là lỗi chặn, kể cả với `--force`.
|
|
573
|
+
>
|
|
574
|
+
> Dùng khi: tech-doc bump revision có đụng thật phần điều khiển UC này, hoặc cần dựng lại code cho một scenario đang `OK`. **Đọc diff của nguồn TRƯỚC** — nếu revision bump không đụng UC này (vd chỉ thêm UC khác vào doc gộp) thì sinh lại code chỉ để đồng bộ một dòng nhãn là rủi ro không đáng.
|
|
575
|
+
|
|
556
576
|
**Xác định `fe_full`:** khi **KHÔNG** có `--phase` VÀ `@trace.platform` là `web`/`app` → đây là **FE full mode**. Sinh UI **và** wire API thật trong cùng một lần chạy, **bỏ qua** layer mock. Cụ thể: các section **sinh UI** chạy · **Mock API Layer** bị bỏ (chỉ dành `--phase=ui`) · **DS4** và **Integration Phase** VẪN chạy (xem điều kiện của từng section). BE/`system` ở default vẫn là full backend như trước.
|
|
557
577
|
|
|
558
578
|
**Nếu `--phase` được set — xác nhận platform:**
|
|
@@ -677,8 +697,9 @@ Phân giải design điều khiển adapter từ **tech-doc gộp của PRD** `{
|
|
|
677
697
|
|--------|---------|-------------------|
|
|
678
698
|
| `UNTRACKED` | `implemented_by == —` | Generate — scenario chưa có code |
|
|
679
699
|
| `DRIFT` | `spec_ver != gen_ver` | Sửa **tại chỗ đúng method** của scenario đó (Edit) — KHÔNG viết lại cả file (file chung sẽ mất method UC khác) |
|
|
680
|
-
| `OK` | đã implement + test | Skip trừ khi
|
|
700
|
+
| `OK` | đã implement + test | **Skip** — trừ khi có `--force` (xem §Phase Detection). Sinh lại thì sửa **tại chỗ đúng method** (Edit), như hàng `DRIFT`.<br/>*(Tới đây vì cờ ⓘ `PRD_STALE_REF`/`TECHDOC_STALE_REF`? **Sai lệnh.** Hai cờ đó nghĩa là version bump KHÔNG đụng UC này — dùng `/validate-traces --realign-prd-version {UC-ID}` (chỉ sửa dòng nhãn, không đụng logic). Chỉ dùng `--force` khi cờ là 🟠 `PRD_DRIFT`/`TECHDOC_DRIFT` — nội dung đổi thật.)* |
|
|
681
701
|
| `GAP` | đã implement, chưa test | Skip codegen — đã code rồi; chạy `/dev-gen-test` thay vì |
|
|
702
|
+
| `ORPHANED` | SC không còn trong `.feature` nhưng code còn | **Skip codegen** — không có scenario nào để implement. **KHÔNG xoá** code/row (cần người quyết định behavior đó còn cần hay không). Nêu ở report cuối: `⚠️ {sc_id} ORPHANED — code {implemented_by} còn tồn tại nhưng scenario đã bị xoá khỏi .feature. Xử: xoá code+test, hoặc đưa scenario trở lại. (/validate-traces giữ cờ 🔴.)` |
|
|
682
703
|
|
|
683
704
|
Dùng các status này để điền số **Scenarios** trong plan CHECKPOINT (`{X} new, {Y} drifted, {Z} synced-skip`).
|
|
684
705
|
Nếu `.tsv` không tồn tại → coi mọi scenario là `UNTRACKED`.
|
|
@@ -874,16 +895,39 @@ DTOs → Entity/Model → Repository → Service interface → Service impl →
|
|
|
874
895
|
@trace.prd_version={đọc @trace.prd_version từ header file .feature}
|
|
875
896
|
@trace.bdd_version={đọc @trace.bdd_version từ header file .feature}
|
|
876
897
|
@trace.tech_doc_revision={đọc @trace.revision từ header tech-doc, hoặc bỏ nếu không có tech-doc}
|
|
877
|
-
@trace.
|
|
898
|
+
@trace.design_spec_version={CHỈ FE/App (@trace.platform = web|app): đọc | **Version** | từ Metadata design-spec đã nạp. BỎ HẲN dòng này với system/backend}
|
|
899
|
+
@trace.source={paths.specs_dir}/{domain}/{prd-slug}/bdd/{@trace.platform}/{UC-ID}-{slug}.feature
|
|
878
900
|
```
|
|
879
901
|
|
|
880
902
|
`@trace.prd_version` ghi code này được viết theo version PRD nào.
|
|
881
903
|
`@trace.bdd_version` ghi code này được sinh từ version BDD nào.
|
|
882
904
|
`@trace.tech_doc_revision` ghi code này theo revision tech-design nào.
|
|
905
|
+
`@trace.design_spec_version` *(chỉ FE/App)* ghi code này dựng theo version design-spec nào — nguồn của `DESIGNSPEC_DRIFT`. **Vì sao cần:** design-spec là input BẮT BUỘC của code FE (màn hình, component inventory, link Figma frame) và của cả BDD FE/App, nhưng trước đây nó là artifact upstream **DUY NHẤT** không có cột TSV, không có tag trong code, không có cờ drift — designer sửa design-spec sau khi code đã sinh thì không gì phát hiện được.
|
|
883
906
|
`/validate-traces` sẽ gắn cờ drift nếu bất kỳ artifact upstream nào được cập nhật lên version mới hơn.
|
|
884
907
|
|
|
885
908
|
> **Quy tắc entry-point:** `@trace.implements` phải xuất hiện ở **layer entry-point** như định nghĩa trong `CLAUDE.md §2`. Với REST API → Controller. Với module event-driven → event handler / consumer class. Với context-engineering → hàm orchestration prompt. Không bao giờ chỉ đặt ở layer trong.
|
|
886
909
|
|
|
910
|
+
> **File phủ NHIỀU UC → lặp CẢ BLOCK 5 tag, đặt trên method của từng UC. CẤM trỏ thư mục, CẤM gộp về một header file.**
|
|
911
|
+
>
|
|
912
|
+
> Đây là hình dạng đúng:
|
|
913
|
+
> ```
|
|
914
|
+
> // @trace.implements=USR-UC1-SC3
|
|
915
|
+
> // @trace.prd_version=1.2 @trace.bdd_version=1.4 @trace.tech_doc_revision=3
|
|
916
|
+
> // @trace.source=specs/user/create-account/bdd/system/USR-UC1-create-account.feature
|
|
917
|
+
> public AccountDto createAccount(...) { }
|
|
918
|
+
>
|
|
919
|
+
> // @trace.implements=USR-UC3-SC1
|
|
920
|
+
> // @trace.prd_version=2.0 @trace.bdd_version=2.1 @trace.tech_doc_revision=5
|
|
921
|
+
> // @trace.source=specs/user/create-account/bdd/system/USR-UC3-verify-email.feature
|
|
922
|
+
> public void verifyEmail(...) { }
|
|
923
|
+
> ```
|
|
924
|
+
>
|
|
925
|
+
> **Vì sao không được gộp:** 3 tag version là **scalar theo từng UC**. Một file phủ UC1 + UC3 mà chỉ có một header thì không diễn đạt được "UC1 ở bdd v1.4, UC3 ở v2.1" → `/validate-traces` Step 4/5/5c báo drift oan hoặc **mù** drift thật. Version phải nằm cạnh member nó mô tả.
|
|
926
|
+
>
|
|
927
|
+
> **Vì sao không được trỏ thư mục** (`@trace.source=…/bdd/system/`): độ phân giải của trace là `UC × SC`, thư mục làm mất cả hai bậc. Và các lệnh tra tag bằng **khớp chuỗi chính xác** (`/dev-gen-test`, `/dev-smoke-test`, `/review-code` đều tìm "file gắn `@trace.implements={UC-ID}`") → tag trỏ folder ra 0 kết quả, UC rơi về `UNTRACKED` dù code đã có.
|
|
928
|
+
>
|
|
929
|
+
> Quy tắc EXTEND ở §File Scan vốn đã yêu cầu giữ **nguyên si** mọi `@trace.implements` cũ *kể cả của UC khác* — tức là thiết kế vốn là **tích luỹ nhiều block**, không phải gộp lại.
|
|
930
|
+
|
|
887
931
|
> **Quy tắc nguồn giá trị (chống hard-code):** MỌI giá trị cụ thể (endpoint path, error code, tên field/DTO, enum, limit/timeout, header) phải lấy từ **nguồn đã chốt** — **KHÔNG bịa inline**. Nếu một hằng số nghiệp vụ lặp lại hoặc mang ý nghĩa (retry count, ngưỡng, key) → **đặt tên hằng số** (constant/config), không rải magic number/string trong code.
|
|
888
932
|
>
|
|
889
933
|
> **VÉT CẠN NGUỒN TRƯỚC KHI HỎI (SRC-CHAIN) — bắt buộc.** Khi một giá trị chưa thấy ở nguồn chính, PHẢI quét lần lượt các nguồn đã có trong context/spec-package theo thứ tự sau, **dừng ngay khi tìm thấy** (skip-if-answered), KHÔNG hỏi người ngay:
|
|
@@ -1009,22 +1053,66 @@ Cập nhật `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{@trace.platform}.ts
|
|
|
1009
1053
|
| `bdd_version` | `@trace.bdd_version` từ header `.feature` |
|
|
1010
1054
|
| `tech_doc_revision` | `@trace.revision` từ tech-doc gộp `{TICKET-ID}-tech-design.md` (§4 backend đã điều khiển codegen của UC này), hoặc `—` nếu chưa có doc |
|
|
1011
1055
|
| `fe_tech_doc_revision` | `@trace.revision` của cùng tech-doc gộp, ghi khi sinh FE có wire adapter theo §4.5.4 (`--phase=integration` **hoặc** `fe_full`); `—` cho BE, hoặc cho FE `--phase=ui` / chưa có §4.5.4 |
|
|
1012
|
-
| `fe_phase` | `ui` nếu `--phase=ui` \| `
|
|
1056
|
+
| `fe_phase` | `ui` nếu `--phase=ui` \| `integration` nếu `--phase=integration` **hoặc** `fe_full` (đều đã wire real adapter) \| `—` cho BE |
|
|
1013
1057
|
| `last_updated` | hôm nay `YYYY-MM-DD` |
|
|
1014
1058
|
|
|
1015
|
-
Giữ nguyên mọi cột khác (`sc_title`, `spec_ver`, `prd_version`, `prd_status`, `uc_status`, `test_count`, `test_classes`, `dev_selftest`, `dev_selftest_at`, `qc_status`, `qc_run_at`, `qc_owner`, `qc_blocked_by`).
|
|
1059
|
+
Giữ nguyên mọi cột khác (`sc_title`, `spec_ver`, `prd_version`, `prd_status`, `uc_status`, `test_count`, `test_classes`, `dev_selftest`, `dev_selftest_at`, `qc_status`, `qc_run_at`, `qc_owner`, `qc_blocked_by`) — **trừ ngoại lệ có kiểm soát ngay dưới đây**: khi logic vừa đổi thật (lấp stub, hoặc sửa method vì `DRIFT`), 4 cột nghiệm thu `dev_selftest`/`dev_selftest_at`/`qc_status`/`qc_run_at` **phải bị hạ** về "chưa biết". Giữ một `pass` đã hết hiệu lực là báo cáo sai, không phải tôn trọng quyền sở hữu cột.
|
|
1016
1060
|
`status` được tính bởi `/validate-traces` — không set ở đây.
|
|
1017
1061
|
|
|
1018
|
-
**
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1062
|
+
**Hạ hiệu lực tín hiệu kiểm thử khi logic vừa đổi thật.** Áp cho **HAI** trường hợp — cùng một lý do, cùng một tập cột *(luật "Làm mất hiệu lực ≠ ghi đè", `rules/workflow.md`)*:
|
|
1063
|
+
|
|
1064
|
+
| Trường hợp | Phạm vi scenario bị ảnh hưởng |
|
|
1065
|
+
|---|---|
|
|
1066
|
+
| **A. Lấp stub** (Fill-before-create — dòng sổ `→ RESOLVED`) | **Mọi** scenario chạy qua method vừa lấp — gồm cả scenario của **consumer_uc** (UC đã để trắng, thường nằm ở file TSV khác `{consumer_uc}-{platform}.tsv`) |
|
|
1067
|
+
| **B. Sửa method vì row đang `DRIFT`** (spec đổi sau lần gen trước) | Đúng các SC vừa được sửa method trong lần chạy này |
|
|
1068
|
+
|
|
1069
|
+
Với mỗi scenario trong phạm vi:
|
|
1070
|
+
- `dev_selftest → not_run` · `dev_selftest_at → —` · `qc_status → not_run` · `qc_run_at → —`.
|
|
1071
|
+
- **CHỈ** đụng 4 cột này — ngoại lệ có kiểm soát của luật "giữ nguyên cột khác" ở trên; là thao tác an-toàn (không sửa code UC khác, chỉ hạ cờ nghiệm thu đã hết hiệu lực).
|
|
1072
|
+
- **KHÔNG** đụng `test_count`/`test_classes` (test vẫn tồn tại — số lượng không sai, chỉ nội dung cũ; hạ số sẽ làm tỷ lệ coverage nhảy loạn) và **KHÔNG** đụng `qc_owner`/`qc_blocked_by` (con trỏ tới bug — code đổi không làm bug biến mất).
|
|
1073
|
+
- Gom danh sách `{consumer_uc}` bị ảnh hưởng (trường hợp A) để in ở "Next".
|
|
1074
|
+
|
|
1075
|
+
> **Vì sao trường hợp B cũng phải hạ:** lý do giống hệt A — logic vừa đổi thật, nên test cũ đang nghiệm thu một hành vi không còn tồn tại. Trước đây chỉ A được xử lý, nên chuỗi "spec đổi → `DRIFT` → sửa code → `OK`" kết thúc với `qc_status = pass` từ lần QC chạy trên **spec cũ**, và dashboard hiện xanh hoàn toàn. `/fix-bug` đã làm đúng việc này từ trước với chính lời giải thích đó: *"code vừa đổi nên tín hiệu self-test cũ hết hiệu lực"*.
|
|
1076
|
+
|
|
1077
|
+
Bất kể trường hợp nào, in khối này ở report cuối để dev không tưởng là hệ thống hỏng:
|
|
1078
|
+
```
|
|
1079
|
+
🔻 Tín hiệu kiểm thử bị hạ ({spec vừa đổi | vừa lấp stub} — nghiệm thu cũ hết hiệu lực):
|
|
1080
|
+
{sc_id}: dev_selftest pass→not_run · qc_status pass→not_run
|
|
1081
|
+
⚠️ {n} test của các SC này viết cho bản cũ — rà lại nội dung, đừng chỉ chạy lại.
|
|
1082
|
+
→ /dev-run-test {UC-ID} rồi QC chạy /qc-run-test {UC-ID}
|
|
1083
|
+
ℹ️ Coverage "đã kiểm đạt" trên dashboard sẽ TỤT sau lần này — đó là số đúng;
|
|
1084
|
+
số cũ mới là số sai. (Tỷ lệ phủ code/test không đổi — test_count giữ nguyên.)
|
|
1085
|
+
```
|
|
1022
1086
|
|
|
1023
1087
|
## Refresh Panel Mirror
|
|
1024
|
-
# Làm mới panel mirror của Living Docs *(local
|
|
1088
|
+
# Làm mới panel mirror của Living Docs *(local)*
|
|
1089
|
+
|
|
1090
|
+
> **Hai vị trí, HAI TÊN KHÁC NHAU — đọc trước khi sửa gì ở đây.**
|
|
1091
|
+
>
|
|
1092
|
+
> | Đường dẫn | Vai trò | Git |
|
|
1093
|
+
> |---|---|---|
|
|
1094
|
+
> | `{paths.trace_dir}` (`.trace/` hoặc `{spec_source}/.trace/`) | **AUTHORITATIVE** — TSV + `trace-history.jsonl`. Không regenerate được. | **PHẢI commit** |
|
|
1095
|
+
> | `./.trace-mirror/` ở gốc workspace hiện tại | **MIRROR** — bản sao tiện cho panel VS Code. Sinh lại được bất cứ lúc nào. | **Luôn gitignore** |
|
|
1096
|
+
>
|
|
1097
|
+
> Trước v0.4.3 cả hai đều tên `.trace`, nên một luật gitignore theo tên có thể **xoá sạch sổ gốc**
|
|
1098
|
+
> khi dev mở thẳng spec repo làm workspace (lúc đó hai path bằng nhau). Hai tên khác nhau làm
|
|
1099
|
+
> luật git đọc được bằng mắt và **không còn ca nhập nhằng nào**: `.trace-mirror/` không bao giờ
|
|
1100
|
+
> commit, `.trace/` không bao giờ gitignore.
|
|
1101
|
+
|
|
1102
|
+
## Khi nào CÓ mirror
|
|
1025
1103
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1104
|
+
Mirror chỉ tồn tại khi **`{paths.trace_dir}` nằm NGOÀI workspace hiện tại** — panel đọc từ workspace đang mở nên cần một bản sao ở đây.
|
|
1105
|
+
|
|
1106
|
+
| Tình huống | `{paths.trace_dir}` | Có mirror? |
|
|
1107
|
+
|---|---|---|
|
|
1108
|
+
| Single-service | `./.trace` — **trong** workspace | ❌ Không. Panel đọc thẳng `.trace/trace-report.json`. Bỏ qua cả file này. |
|
|
1109
|
+
| Dev mở thẳng **spec repo** | `./.trace` — **trong** workspace | ❌ Không. Như trên. |
|
|
1110
|
+
| Umbrella + `spec_source`, dev đứng ở umbrella hoặc service submodule | `{spec_source}/.trace` — **ngoài** workspace | ✅ Có |
|
|
1111
|
+
| Umbrella legacy (không `spec_source`) | `.trace` theo từng service | ✅ Có |
|
|
1112
|
+
|
|
1113
|
+
Quy tắc một dòng: **phân giải `panel_mirror = ./.trace-mirror` ở gốc workspace hiện tại; nếu `{paths.trace_dir}` đã nằm trong workspace này thì bỏ qua toàn bộ bước mirror.**
|
|
1114
|
+
|
|
1115
|
+
---
|
|
1028
1116
|
|
|
1029
1117
|
Sau khi cập nhật TSV authoritative tại `{paths.trace_dir}`:
|
|
1030
1118
|
|
|
@@ -1032,11 +1120,14 @@ Sau khi cập nhật TSV authoritative tại `{paths.trace_dir}`:
|
|
|
1032
1120
|
`{paths.trace_dir}` phân giải về `{spec_source}/.trace` — vị trí authoritative duy nhất.
|
|
1033
1121
|
Lệnh này chạy từ `service_root`, nên thao tác ghi là **liên-repo vào spec submodule**;
|
|
1034
1122
|
commit/push spec submodule cho lần cập nhật trace (giống như `feedback/`).
|
|
1035
|
-
|
|
1036
|
-
|
|
1123
|
+
|
|
1124
|
+
1. Phân giải `panel_mirror = ./.trace-mirror` tại **gốc workspace hiện tại**.
|
|
1125
|
+
2. Nếu `{paths.trace_dir}` **không** nằm trong workspace hiện tại, copy mỗi
|
|
1037
1126
|
`{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{UC-ID}-{platform}.tsv` (tạo thư mục; ghi đè).
|
|
1038
|
-
Không namespace theo service — chỉ có một bộ trace; service sở hữu được mang
|
|
1039
|
-
|
|
1127
|
+
Không namespace theo service — chỉ có một bộ trace; service sở hữu được mang ở
|
|
1128
|
+
**cột `service` (cột 23)** của chính từng row, do `/generate-bdd` ghi từ `@trace.service`.
|
|
1129
|
+
3. **KHÔNG copy `trace-history.jsonl`.** Nó là dữ liệu tích luỹ, không phải thứ sinh lại được —
|
|
1130
|
+
nhân bản nó ra một thư mục gitignore là tạo hai lịch sử lệch nhau rồi mất bản thật.
|
|
1040
1131
|
|
|
1041
1132
|
**Legacy (không có `spec_source` — trace theo service):**
|
|
1042
1133
|
Copy mỗi `{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{service-name}/{UC-ID}-{platform}.tsv`
|
|
@@ -1093,7 +1184,7 @@ Tìm lệnh hiện tại trong bảng phase dưới đây và đánh dấu **pha
|
|
|
1093
1184
|
| Phase | Commands |
|
|
1094
1185
|
|-------|----------|
|
|
1095
1186
|
| Discovery | `/define-product` |
|
|
1096
|
-
| PRD | `/generate-prd` · `/refine-prd` · `/review-context` (PRD) |
|
|
1187
|
+
| PRD | `/generate-prd` · `/extend-prd` · `/refine-prd` · `/review-context` (PRD) |
|
|
1097
1188
|
| Design Spec | `/generate-design-spec` |
|
|
1098
1189
|
| BDD | `/generate-bdd` · `/review-context` (BDD) |
|
|
1099
1190
|
| Tech Design | `/generate-tech-docs` · `/map-testids` · `/review-tech-docs` |
|
|
@@ -1118,6 +1209,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
|
|
|
1118
1209
|
| /setup-ai-first | `/define-product` để bắt đầu feature đầu tiên |
|
|
1119
1210
|
| /define-product | `/generate-prd {product-definition-file}` |
|
|
1120
1211
|
| /generate-prd | `/refine-prd {prd-file}` rồi `/review-context {prd-file}` |
|
|
1212
|
+
| /extend-prd | `/refine-prd {prd-file}` (soi phần vừa thêm) rồi `/review-context {prd-file}` → PO duyệt → `/generate-bdd` **chỉ cho UC MỚI**; UC cũ dùng `/validate-traces --realign-prd-version {UC-ID}` |
|
|
1121
1213
|
| /refine-prd | Mở Review Board → cập nhật PRD → `/review-context {prd-file}` |
|
|
1122
1214
|
| /review-context (PRD) | Khi 0 critical → PO đặt `Status: approved`, rồi FE/App: `/generate-design-spec {prd-file}` (→ design sign-off → BDD); BE: `/generate-bdd {prd-file}`. Còn critical/NEEDS_FIX → sửa PRD (giữ draft) |
|
|
1123
1215
|
| /generate-design-spec | Designer review → xác nhận link Figma → PO + Designer sign-off → `/generate-bdd {prd-file}` |
|
|
@@ -1130,6 +1222,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
|
|
|
1130
1222
|
| /qc-run-test | `/qc-report {UC-ID}` rồi `/qc-review {UC-ID}` (review script) |
|
|
1131
1223
|
| /qc-review (script) | `/qc-report {UC-ID}` rồi tạo PR nếu APPROVED |
|
|
1132
1224
|
| /qc-report | `/validate-traces {UC-ID}` để làm mới Living Docs (qc_status) |
|
|
1225
|
+
| /map-testids | `/qc-design-test {UC-ID}` (QC dựng Page Object từ contract §4.5.6 vừa ghi) |
|
|
1133
1226
|
| /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
|
|
1134
1227
|
| /review-tech-docs | `/generate-code {feature-file}` nếu APPROVED; sửa doc nếu NEEDS_FIX |
|
|
1135
1228
|
| /generate-code | Lần gen đầu → `/review-code {UC-ID}`; gen lại → `/dev-gen-test {UC-ID}` |
|
|
@@ -1138,11 +1231,11 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
|
|
|
1138
1231
|
| /dev-run-test (failing) | `/fix-bug {ticket-id}` hoặc `/debug {error}` |
|
|
1139
1232
|
| /review-code | `/dev-smoke-test {UC-ID}` hoặc tạo PR |
|
|
1140
1233
|
| /dev-smoke-test | Tạo PR và link tới ticket |
|
|
1141
|
-
| /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}
|
|
1142
|
-
| /fix-bug |
|
|
1234
|
+
| /validate-traces | **Cờ 🔴 trước (chặn PR):** SEAM_UNWIRED → nối binding sang class thật, xoá/thay stub · STUB_UNRESOLVED → `/generate-code {owner_uc}` (lấp logic tại chỗ + xoá hàm song song) · ORPHANED/TRACE_ORPHAN → quyết định thủ công (xoá code+test, đưa scenario trở lại `.feature`, hoặc sửa `sc_id` của tag). **Rồi:** DRIFT/UNTRACKED → `/generate-code {UC-ID}` · BDD_DRIFT → `/generate-code {feature-file}` · tech-doc lỗi thời vs BDD → `/generate-tech-docs` → `/review-tech-docs` · PRD drift → `/generate-bdd {prd-file}` · GAP → `/dev-gen-test {UC-ID}`. **Chỉ tạo PR khi mọi cờ 🔴 = 0** |
|
|
1235
|
+
| /fix-bug | `/dev-run-test {UC-ID}` (dev_selftest vừa reset về not_run) → tạo PR; nếu fix một `{BUG-ID}` → QC chạy `/qc-run-test {UC-ID}` để verify + đóng bug |
|
|
1143
1236
|
| /debug | `/fix-bug {ticket-id}` nếu cần sửa |
|
|
1144
1237
|
| /report-bug | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
|
|
1145
|
-
| /propose-scenario |
|
|
1238
|
+
| /propose-scenario | **Case A** (thiếu scenario cho AC có sẵn) → báo PO/Dev review trong `feedback/bdd-proposals/`; `/generate-bdd` tự chèn khi `Status: accepted`. **Case B** (requirement mới) → `feedback/prd-change-requests/` — PO phải đưa vào PRD trước, KHÔNG tự vào BDD được; `/validate-traces` nhắc lại kèm số ngày chờ chừng nào `Status: Open` |
|
|
1146
1239
|
| /learn | Tiếp tục làm việc — lesson áp dụng ở lệnh kế tiếp |
|
|
1147
1240
|
| /sync | `/validate-traces` để xem độ phủ đầy đủ; xử lý mọi `📥 tester feedback` được nêu |
|
|
1148
1241
|
| /update-framework | Review `git diff .agent/`, commit; `/sync` để đồng bộ nội dung dự án |
|
|
@@ -1164,7 +1257,7 @@ Next : {lệnh gợi ý kèm ví dụ tham số}
|
|
|
1164
1257
|
Files: created={N}, extended={M}, filled={F} stub, skipped={K} | Build: SUCCESS
|
|
1165
1258
|
Branch: feature/{TICKET_ID}-{slug}
|
|
1166
1259
|
Phase : {UI (mock layer) | Integration (real API) | FE full (UI + real API) | BE full}
|
|
1167
|
-
fe_phase : {ui |
|
|
1260
|
+
fe_phase : {ui | integration (—phase=integration | fe_full) | —}
|
|
1168
1261
|
Figma : {Dev Mode MCP local (grounded) | ⚠️ chỉ link web + text spec (không có MCP local) | n/a cho BE} ← chỉ UI FE/App
|
|
1169
1262
|
|
|
1170
1263
|
Next:
|