@educa-corp/sdd-framework 0.4.2 → 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/self-check.js +124 -6
- package/bin/trace-schema.json +1199 -692
- package/commands/debug.md +3 -2
- package/commands/define-product.md +3 -2
- package/commands/dev-gen-test.md +37 -9
- package/commands/dev-run-test.md +37 -9
- package/commands/dev-smoke-test.md +3 -2
- package/commands/extend-prd.md +907 -0
- package/commands/extend-prd.tmpl +270 -0
- package/commands/fix-bug.md +37 -9
- package/commands/generate-architecture.md +3 -2
- package/commands/generate-bdd.md +56 -13
- package/commands/generate-bdd.tmpl +18 -3
- package/commands/generate-code.md +73 -16
- package/commands/generate-code.tmpl +36 -7
- package/commands/generate-design-spec.md +3 -2
- package/commands/generate-prd.md +28 -2
- package/commands/generate-prd.tmpl +25 -0
- package/commands/generate-spec-manifest.md +3 -2
- package/commands/generate-tech-docs.md +3 -2
- package/commands/learn.md +3 -2
- package/commands/map-testids.md +3 -2
- package/commands/propose-scenario.md +55 -3
- package/commands/propose-scenario.tmpl +52 -1
- package/commands/qc-analyze.md +3 -2
- package/commands/qc-design-test.md +4 -2
- package/commands/qc-design-test.tmpl +1 -0
- package/commands/qc-plan.md +3 -2
- package/commands/qc-report.md +3 -2
- package/commands/qc-review.md +3 -2
- package/commands/qc-run-test.md +50 -10
- package/commands/qc-run-test.tmpl +13 -1
- package/commands/refine-prd.md +3 -2
- package/commands/report-bug.md +3 -2
- package/commands/review-code.md +7 -5
- package/commands/review-code.tmpl +4 -3
- package/commands/review-context.md +6 -4
- package/commands/review-context.tmpl +3 -2
- package/commands/review-tech-docs.md +3 -2
- package/commands/setup-ai-first.md +3 -2
- package/commands/sync.md +40 -16
- package/commands/sync.tmpl +37 -14
- package/commands/update-framework.md +3 -2
- package/commands/validate-traces.md +318 -33
- package/commands/validate-traces.tmpl +315 -31
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/debug.md +3 -2
- package/core/commands/define-product.md +3 -2
- package/core/commands/dev-gen-test.md +37 -9
- package/core/commands/dev-run-test.md +37 -9
- package/core/commands/dev-smoke-test.md +3 -2
- package/core/commands/extend-prd.md +907 -0
- package/core/commands/fix-bug.md +37 -9
- package/core/commands/generate-architecture.md +3 -2
- package/core/commands/generate-bdd.md +56 -13
- package/core/commands/generate-code.md +73 -16
- package/core/commands/generate-design-spec.md +3 -2
- package/core/commands/generate-prd.md +28 -2
- package/core/commands/generate-spec-manifest.md +3 -2
- package/core/commands/generate-tech-docs.md +3 -2
- package/core/commands/learn.md +3 -2
- package/core/commands/map-testids.md +3 -2
- package/core/commands/propose-scenario.md +55 -3
- package/core/commands/qc-analyze.md +3 -2
- package/core/commands/qc-design-test.md +4 -2
- package/core/commands/qc-plan.md +3 -2
- package/core/commands/qc-report.md +3 -2
- package/core/commands/qc-review.md +3 -2
- package/core/commands/qc-run-test.md +50 -10
- package/core/commands/refine-prd.md +3 -2
- package/core/commands/report-bug.md +3 -2
- package/core/commands/review-code.md +7 -5
- package/core/commands/review-context.md +6 -4
- package/core/commands/review-tech-docs.md +3 -2
- package/core/commands/setup-ai-first.md +3 -2
- package/core/commands/sync.md +40 -16
- package/core/commands/update-framework.md +3 -2
- package/core/commands/validate-traces.md +318 -33
- package/core/rules/workflow.md +18 -0
- package/core/steps/report-footer.md +3 -2
- package/core/steps/trace-mirror.md +34 -7
- package/core/templates/feature.template +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 -117
- 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 +26 -9
- 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/package.json +50 -50
- package/rules/workflow.md +18 -0
- package/steps/report-footer.md +3 -2
- package/steps/trace-mirror.md +34 -7
- package/templates/feature.template +1 -1
|
@@ -1,7 +1,31 @@
|
|
|
1
|
-
# Làm mới panel mirror của Living Docs *(local
|
|
1
|
+
# Làm mới panel mirror của Living Docs *(local)*
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
> **Hai vị trí, HAI TÊN KHÁC NHAU — đọc trước khi sửa gì ở đây.**
|
|
4
|
+
>
|
|
5
|
+
> | Đường dẫn | Vai trò | Git |
|
|
6
|
+
> |---|---|---|
|
|
7
|
+
> | `{paths.trace_dir}` (`.trace/` hoặc `{spec_source}/.trace/`) | **AUTHORITATIVE** — TSV + `trace-history.jsonl`. Không regenerate được. | **PHẢI commit** |
|
|
8
|
+
> | `./.trace-mirror/` ở gốc workspace hiện tại | **MIRROR** — bản sao tiện cho panel VS Code. Sinh lại được bất cứ lúc nào. | **Luôn gitignore** |
|
|
9
|
+
>
|
|
10
|
+
> Trước v0.4.3 cả hai đều tên `.trace`, nên một luật gitignore theo tên có thể **xoá sạch sổ gốc**
|
|
11
|
+
> khi dev mở thẳng spec repo làm workspace (lúc đó hai path bằng nhau). Hai tên khác nhau làm
|
|
12
|
+
> luật git đọc được bằng mắt và **không còn ca nhập nhằng nào**: `.trace-mirror/` không bao giờ
|
|
13
|
+
> commit, `.trace/` không bao giờ gitignore.
|
|
14
|
+
|
|
15
|
+
## Khi nào CÓ mirror
|
|
16
|
+
|
|
17
|
+
Mirror chỉ tồn tại khi **`{paths.trace_dir}` nằm NGOÀI workspace hiện tại** — panel đọc từ workspace đang mở nên cần một bản sao ở đây.
|
|
18
|
+
|
|
19
|
+
| Tình huống | `{paths.trace_dir}` | Có mirror? |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Single-service | `./.trace` — **trong** workspace | ❌ Không. Panel đọc thẳng `.trace/trace-report.json`. Bỏ qua cả file này. |
|
|
22
|
+
| Dev mở thẳng **spec repo** | `./.trace` — **trong** workspace | ❌ Không. Như trên. |
|
|
23
|
+
| Umbrella + `spec_source`, dev đứng ở umbrella hoặc service submodule | `{spec_source}/.trace` — **ngoài** workspace | ✅ Có |
|
|
24
|
+
| Umbrella legacy (không `spec_source`) | `.trace` theo từng service | ✅ Có |
|
|
25
|
+
|
|
26
|
+
Quy tắc một dòng: **phân giải `panel_mirror = ./.trace-mirror` ở gốc workspace hiện tại; nếu `{paths.trace_dir}` đã nằm trong workspace này thì bỏ qua toàn bộ bước mirror.**
|
|
27
|
+
|
|
28
|
+
---
|
|
5
29
|
|
|
6
30
|
Sau khi cập nhật TSV authoritative tại `{paths.trace_dir}`:
|
|
7
31
|
|
|
@@ -9,11 +33,14 @@ Sau khi cập nhật TSV authoritative tại `{paths.trace_dir}`:
|
|
|
9
33
|
`{paths.trace_dir}` phân giải về `{spec_source}/.trace` — vị trí authoritative duy nhất.
|
|
10
34
|
Lệnh này chạy từ `service_root`, nên thao tác ghi là **liên-repo vào spec submodule**;
|
|
11
35
|
commit/push spec submodule cho lần cập nhật trace (giống như `feedback/`).
|
|
12
|
-
|
|
13
|
-
|
|
36
|
+
|
|
37
|
+
1. Phân giải `panel_mirror = ./.trace-mirror` tại **gốc workspace hiện tại**.
|
|
38
|
+
2. Nếu `{paths.trace_dir}` **không** nằm trong workspace hiện tại, copy mỗi
|
|
14
39
|
`{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{UC-ID}-{platform}.tsv` (tạo thư mục; ghi đè).
|
|
15
|
-
Không namespace theo service — chỉ có một bộ trace; service sở hữu được mang
|
|
16
|
-
|
|
40
|
+
Không namespace theo service — chỉ có một bộ trace; service sở hữu được mang ở
|
|
41
|
+
**cột `service` (cột 23)** của chính từng row, do `/generate-bdd` ghi từ `@trace.service`.
|
|
42
|
+
3. **KHÔNG copy `trace-history.jsonl`.** Nó là dữ liệu tích luỹ, không phải thứ sinh lại được —
|
|
43
|
+
nhân bản nó ra một thư mục gitignore là tạo hai lịch sử lệch nhau rồi mất bản thật.
|
|
17
44
|
|
|
18
45
|
**Legacy (không có `spec_source` — trace theo service):**
|
|
19
46
|
Copy mỗi `{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{service-name}/{UC-ID}-{platform}.tsv`
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# @trace.revision: 1 ← field tĩnh; version theo dõi bằng @trace.bdd_version
|
|
5
5
|
# @trace.domain: <domain>
|
|
6
6
|
# @trace.platform: {active_platform — web | app | system} ← BẮT BUỘC mọi mode; phải khớp segment bdd/{platform}/ của path
|
|
7
|
-
# @trace.service: {active_service —
|
|
7
|
+
# @trace.service: {active_service — BẮT BUỘC mọi mode. "—" ở single-service/spec repo mode; "multi" nếu chưa chốt; "unresolved" nếu routing sai. Nguồn của cột TSV `service` — trace gộp không tách theo service nên đây là chỗ DUY NHẤT mang thông tin sở hữu}
|
|
8
8
|
# @trace.module: {active_module trong umbrella mode; "unknown" trong spec repo mode}
|
|
9
9
|
# @trace.status: draft
|
|
10
10
|
# @trace.author: AI-generated
|
|
@@ -77,12 +77,29 @@ AI *follow* các file này — để trống thì nó *đoán*:
|
|
|
77
77
|
|
|
78
78
|
| Lệnh | Việc | Ghi đè | KHÔNG đụng |
|
|
79
79
|
|------|------|--------|-----------|
|
|
80
|
-
| `/update-framework` | Sync bản npm mới | `.agent/commands\|steps\|hooks\|rules\|templates\|skills\|modules` | `CLAUDE.md`,
|
|
80
|
+
| `/update-framework` | Sync bản npm mới | `.agent/commands\|steps\|hooks\|rules\|templates\|skills\|modules` | `CLAUDE.md`, `.agent/project-context.yaml`, `.agent/project-lessons.md`, `.agent/review/`, `domain-knowledge/`, `.trace/`, `feedback/` |
|
|
81
81
|
| `/sync` (umbrella) | Pull + init submodule + nổi feedback + Living Docs | — | — |
|
|
82
82
|
|
|
83
83
|
Kiểm tra version mới nhất: `npm view @educa-corp/sdd-framework version`.
|
|
84
84
|
|
|
85
85
|
> **Quy tắc edit (critical):** `.tmpl` + `steps/` là source of truth. Sửa framework artifact phải sửa `.tmpl`/`steps` rồi `node bin/build.js`. Sửa thẳng `.agent/commands/*.md` sẽ **mất** khi rebuild/update.
|
|
86
|
+
>
|
|
87
|
+
> Từ v0.4.2, nâng cấp **cứu** file bạn đã sửa trong vùng ghi đè: bản cũ lưu ở `.agent/.overwritten-{version}-{date}/` và danh sách được in ra. Ranh giới vùng-sửa-được đầy đủ: `.agent/README.md`. Chi tiết cơ chế: [Configuration › Vùng nào bị ghi đè](../04-reference/configuration.md#vùng-nào-bị-ghi-đè-khi-update).
|
|
88
|
+
|
|
89
|
+
### Migration bố cục spec
|
|
90
|
+
|
|
91
|
+
Một số version đổi **bố cục** chứ không chỉ nội dung lệnh. `/update-framework` Step 5.5 tự quét và nhắc, hoặc chạy tay (đều **dry-run mặc định**, thêm `--apply` để thực thi):
|
|
92
|
+
|
|
93
|
+
| Lệnh | Khi nào cần |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `--migrate-bdd-platform` | Có `.feature` nằm **trực tiếp** dưới `bdd/` (bố cục phẳng trước v0.4.1) → chuyển sang `bdd/{platform}/`. Bố cục phẳng làm `web`/`system` cùng UC **va tên và ghi đè nhau**. |
|
|
96
|
+
| `--migrate-specs` | Còn `specs/prd/` hay `specs/bdd/` ở cấp gốc (bố cục artifact-type-first rất cũ) |
|
|
97
|
+
| `--rename-prd-files` | PRD còn tên cố định `prd.md` thay vì `{TICKET-ID}-{prd-slug}.md` |
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npx @educa-corp/sdd-framework --migrate-bdd-platform # xem plan
|
|
101
|
+
npx @educa-corp/sdd-framework --migrate-bdd-platform --apply # thực thi
|
|
102
|
+
```
|
|
86
103
|
|
|
87
104
|
---
|
|
88
105
|
|
|
@@ -26,8 +26,10 @@ Dùng AI tự do (mở chat, gõ prompt, copy-paste) → AI suy diễn theo tr
|
|
|
26
26
|
| Vấn đề | Cách giải |
|
|
27
27
|
|--------|-----------|
|
|
28
28
|
| AI viết lung tung, không bám requirement | Spec là **anchor cứng**; code link `@trace.source` về scenario |
|
|
29
|
-
| Sửa code → spec lệch → AI hiểu sai lần sau | **Spec là
|
|
30
|
-
| Sửa spec → không biết code nào cần regen | **Trace state `.tsv
|
|
29
|
+
| Sửa code → spec lệch → AI hiểu sai lần sau | **Spec là SSOT của "bản hiện tại"**; code mang version của "bản tôi được sinh theo" — **lệch nhau chính là tín hiệu drift** |
|
|
30
|
+
| Sửa spec → không biết code nào cần regen | **Trace state `.tsv`** một sổ / UC × platform → `OK`/`GAP`/`DRIFT`/`UNTRACKED`/`ORPHANED` |
|
|
31
|
+
| Xoá scenario → code mồ côi nằm im | **Quét ngược code → spec**; code trỏ vào SC không còn tồn tại bị gắn cờ 🔴, không tự hết |
|
|
32
|
+
| Build xanh nhưng ghép luồng chạy vào no-op | **Sổ seam/stub** — bắt lớp lỗi mà build + test từng-UC không thấy |
|
|
31
33
|
| PRD/BDD kém → code rác hàng loạt | **Quality gate** (`/review-context`) phải sạch critical + PO approve |
|
|
32
34
|
| Lỗi/định hướng sai lặp lại | **`/learn`** ghi lesson, nạp lại vào context |
|
|
33
35
|
| Đổi tech stack → viết lại workflow | **Module overlay** — skill đọc `stack-profile.yaml`, không hardcode |
|
|
@@ -62,13 +62,37 @@ Spec-driven thành/bại phụ thuộc **~80%** vào việc context được n
|
|
|
62
62
|
|
|
63
63
|
```
|
|
64
64
|
.tmpl (source) + steps/*.md --[node bin/build.js, {{include:...}}]--> commands/*.md + core/
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
│ │
|
|
66
|
+
│ templates/*.template* cũng được inline │
|
|
67
|
+
▼ ▼
|
|
68
|
+
bin/self-check.js (fail build) .agent/commands/*.md (runtime)
|
|
68
69
|
```
|
|
69
70
|
|
|
70
71
|
- Cơ chế `{{include:steps/...}}` ghép phẳng → single source of truth ở `.tmpl` + `steps/`.
|
|
71
72
|
- **Không sửa tay** `commands/*.md` / `.agent/` — sửa `.tmpl`/`steps` rồi `node bin/build.js`. *(Quy ước + memory bảo vệ, không phải hook.)*
|
|
73
|
+
- **Template artifact cũng bị inline lúc build.** `templates/feature.template` và `prd.template.md` được `{{include}}` **nướng cứng** vào file lệnh, nên lệnh không đọc path template lúc chạy — sửa `.agent/templates/` **không có tác dụng**. Đổi cấu trúc `.feature`/PRD = sửa `templates/*` trong repo framework rồi build lại.
|
|
74
|
+
|
|
75
|
+
### Self-check — contract trace không được lệch
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
bin/trace-schema.json ──[bin/self-check.js]──> đối chiếu commands/*.tmpl + steps/*.md
|
|
79
|
+
(SoT máy đọc) → exit 1 nếu lệch → build FAIL
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Vì sao cần:** phần lớn lỗi lịch sử của framework là **cùng một dạng** — contract (field `@trace.*`, cột `.tsv`, path pattern, giá trị enum) được phát biểu lại bằng **prose** ở nhiều lệnh rồi lệch nhau qua từng lần sửa, và không có gì phát hiện. Ca thuần khiết nhất: `@trace.sc_version` từng có **3 consumer, 0 producer** — nghĩa là `DRIFT` chết hoàn toàn — mà không lệnh nào, cổng nào, test nào bắt được.
|
|
83
|
+
|
|
84
|
+
| Rule | Bắt gì | Mức |
|
|
85
|
+
|:---:|---|:---:|
|
|
86
|
+
| R1 | field có consumer nhưng **không producer** | ERROR |
|
|
87
|
+
| R2 | field có producer nhưng **không ai đọc** (field chết) | WARN |
|
|
88
|
+
| R3 | actor khai trong schema mà file của nó **không nhắc** field | ERROR |
|
|
89
|
+
| R4 | `{paths.X}` dùng mà không khai / khai mà không ai dùng | ERROR / WARN |
|
|
90
|
+
| R5 | pattern bị cấm **quay lại** (vd `bdd/` thiếu `{platform}`) | ERROR |
|
|
91
|
+
| R6 | giá trị enum khai mà **không xuất hiện ở đâu** | WARN |
|
|
92
|
+
|
|
93
|
+
**Quy tắc vận hành:** đổi contract → sửa `bin/trace-schema.json` **TRƯỚC**, rồi mới sửa lệnh, rồi cập nhật [Trace Schema (người đọc)](../04-reference/trace-schema.md). Chạy riêng: `npm run self-check`.
|
|
94
|
+
|
|
95
|
+
*(Schema là JSON chứ không YAML vì `package.json` có **zero dependency** — npx chạy không cần install; thêm `js-yaml` chỉ để đọc một file build-time là không đáng. Nó nằm ở `bin/` chứ không `templates/` để không lọt vào `.agent/templates/` của mọi project.)*
|
|
72
96
|
|
|
73
97
|
---
|
|
74
98
|
|
|
@@ -3,7 +3,17 @@
|
|
|
3
3
|
# Bước 2 · Specification — Hình thành đặc tả (PRD)
|
|
4
4
|
|
|
5
5
|
> **Tóm tắt.** Biến khung intent thành **PRD** chuẩn nghiệp vụ, tinh chỉnh qua 3 lăng kính, rồi qua **gate chất lượng** để PO đóng dấu `approved`.
|
|
6
|
-
> **Commands:** `/generate-prd` → `/refine-prd` → `/review-context`
|
|
6
|
+
> **Commands:** `/generate-prd` (lần đầu) · `/extend-prd` (thêm vào PRD đã có) → `/refine-prd` → `/review-context`
|
|
7
|
+
|
|
8
|
+
> **Chọn lệnh nào — PRD mới vs PRD đã có:**
|
|
9
|
+
>
|
|
10
|
+
> | Tình huống | Lệnh | Vì sao không dùng cái kia |
|
|
11
|
+
> |---|---|---|
|
|
12
|
+
> | PRD **chưa tồn tại** | `/generate-prd` | — |
|
|
13
|
+
> | PRD đã có, **thêm** UC/AC/BR mới | **`/extend-prd`** | `/generate-prd` **từ chối chạy** trên file đã có |
|
|
14
|
+
> | PRD đã có, **sửa vấn đề** đã soi ra | `/refine-prd` → Review Board → `--resume` | `/refine-prd` **không thêm được** yêu cầu mới — nó tự cấm đụng section ngoài findings |
|
|
15
|
+
>
|
|
16
|
+
> **`/generate-prd` dừng hẳn (không hỏi Y/N) nếu file đã tồn tại.** Ghi đè sẽ mất `# Change Log` + rollover, Version/Status thật, và **đánh số lại BR từ đầu** — cái cuối lan **ra ngoài file**, phá mọi `@trace.business_rules` trong `bdd/` đã sinh. Ba mất mát đều không hoàn tác được từ trong lệnh, nên không đặt sau một phím bấm.
|
|
7
17
|
|
|
8
18
|
| | |
|
|
9
19
|
|---|---|
|
|
@@ -29,7 +39,8 @@ PRD là **hợp đồng nghiệp vụ** giữa PO ↔ Dev ↔ AI. Đây là **c
|
|
|
29
39
|
|
|
30
40
|
| Lệnh | Vai trò | Kết quả |
|
|
31
41
|
|------|---------|---------|
|
|
32
|
-
| `/generate-prd` | **Sinh** PRD draft từ product-definition | PRD `Status: draft` |
|
|
42
|
+
| `/generate-prd` | **Sinh** PRD draft từ product-definition. Từ chối chạy nếu PRD đã tồn tại | PRD `Status: draft` |
|
|
43
|
+
| `/extend-prd` | **Thêm** UC/AC/BR vào PRD đã duyệt — đánh số **nối tiếp**, ghi **add-only** + guard sau-ghi, drain `feedback/prd-change-requests/` | PRD v+1, `Status → draft` |
|
|
33
44
|
| `/refine-prd` | **Tinh chỉnh** qua 3 lăng kính DEV/SA/PO (fan-out per-UC) | Findings để PO accept/reject |
|
|
34
45
|
| `/review-context` | **Gate chất lượng** — findings P0–P5, phải sạch critical | PO đặt `Status: approved` |
|
|
35
46
|
|
|
@@ -73,7 +84,32 @@ PRD là **hợp đồng nghiệp vụ** giữa PO ↔ Dev ↔ AI. Đây là **c
|
|
|
73
84
|
|
|
74
85
|
## Framework xử lý thế nào (Mechanics)
|
|
75
86
|
|
|
76
|
-
**`/generate-prd`** — Round Q&A + confirm domain/terminology → sinh PRD draft đúng template, áp Business Language Guard.
|
|
87
|
+
**`/generate-prd`** — Round Q&A + confirm domain/terminology → sinh PRD draft đúng template, áp Business Language Guard. **Guard đầu vào:** file đã tồn tại → dừng hẳn, chỉ sang `/extend-prd`.
|
|
88
|
+
|
|
89
|
+
**`/extend-prd`** — 7 bước, tái dùng tối đa thứ đã có:
|
|
90
|
+
|
|
91
|
+
1. Nạp trạng thái: `max_uc` / `max_br` / `max_ac`, UC hiện có, changelog, BDD đã sinh cho những UC nào
|
|
92
|
+
2. **Drain hàng đợi** `prd-change-requests/` — `accepted` → nguyên liệu; `Open` → trình PO kèm số ngày chờ
|
|
93
|
+
3. Discovery delta — tái dùng Phase 1/4/5/6 của `/define-product` (bỏ Phase 0/2/7 vốn là toàn-feature), **cộng phase "kiểm va chạm"**
|
|
94
|
+
4. **Đánh số nối tiếp** — ràng buộc cứng nhất
|
|
95
|
+
5. Ghi **Edit add-only** + guard sau-ghi
|
|
96
|
+
6. Bump version + changelog — tái dùng **nguyên** `/refine-prd` Phase 3
|
|
97
|
+
7. Report: nêu rõ **UC không đổi** + route `--realign-prd-version` cho chúng
|
|
98
|
+
|
|
99
|
+
**Phase "kiểm va chạm" — `/define-product` không có.** Lúc discovery lần đầu chưa có gì để va chạm; ở đây thì có. Ba câu bắt buộc:
|
|
100
|
+
|
|
101
|
+
| Câu | Vì sao |
|
|
102
|
+
|---|---|
|
|
103
|
+
| Phần thêm làm một BR cũ **sai đi** không? | *(BR cũ "tối đa 5", phần mới cần 20)* → đây là **sửa** BR cũ, không phải thêm mới → bump **major** |
|
|
104
|
+
| Đã có UC/AC nào **phủ một phần** chưa? | → hỏi PO: mở rộng UC cũ hay tạo mới. **Không tự quyết** |
|
|
105
|
+
| Cần dữ liệu/năng lực từ đâu khác? | → ghi vào §1c Phụ thuộc liên service |
|
|
106
|
+
|
|
107
|
+
Va chạm âm thầm là cách một PRD **tự mâu thuẫn với chính nó**.
|
|
108
|
+
|
|
109
|
+
**Hai ràng buộc cứng:**
|
|
110
|
+
|
|
111
|
+
- **Không đánh lại BẤT KỲ ID cũ nào.** UC/AC/BR mới đều là `max + 1`. Số bị bỏ trống (do UC bị xoá ở version trước) **để trống vĩnh viễn** — ID đã từng tồn tại có thể còn bị tham chiếu ở BDD, code, bug report, hoặc PRD khác.
|
|
112
|
+
- **Dòng changelog phải nêu rõ UC/AC/BR.** Đây là **contract**: `/generate-bdd` đọc để quyết cập nhật hẹp (Y) hay gen lại toàn bộ (F), và `/validate-traces` Step 4/5 đọc để lọc `PRD_DRIFT` 🟠 vs `PRD_STALE_REF` ⓘ. Một dòng mơ hồ (`"cập nhật theo yêu cầu mới"`) làm **mất cả hai** bộ lọc cùng lúc.
|
|
77
113
|
|
|
78
114
|
**`/refine-prd`** — fan-out **mỗi UC × 3 lăng kính**:
|
|
79
115
|
- **DEV** — chỗ nào khó hiện thực / thiếu định nghĩa?
|
|
@@ -36,9 +36,14 @@ BDD là **trái tim của traceability**. Mỗi scenario là một đơn vị h
|
|
|
36
36
|
| Artifact | Nội dung |
|
|
37
37
|
|----------|----------|
|
|
38
38
|
| `specs/{domain}/{prd-slug}/bdd/{web\|app\|system}/{UC-ID}*.feature` | Scenario Gherkin + tag `@trace.*` + Coverage Matrix |
|
|
39
|
+
| `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` | Sổ trace — **một sổ cho mỗi UC × platform** |
|
|
39
40
|
| `@trace.status: approved` (sau review) | 🔒 Mở khoá `/generate-tech-docs` |
|
|
40
41
|
|
|
41
|
-
>
|
|
42
|
+
> **Subfolder `{platform}/` LUÔN có — mọi mode, kể cả umbrella.** `web` và `system` của cùng một UC là **hai file khác nhau**; bỏ subfolder thì chúng ra cùng filename và **ghi đè nhau**. Trace cũng tách theo platform, nên bố cục spec phải khớp. Mỗi `.feature` còn mang `@trace.platform` **khớp** segment path của chính nó.
|
|
43
|
+
>
|
|
44
|
+
> Ở umbrella mode, `active_platform` được **suy từ `active_module`** (react/vue/… → `web` · flutter/RN/… → `app` · java-spring/golang/… → `system`); không suy được thì lệnh **dừng và hỏi**, không ghi file.
|
|
45
|
+
>
|
|
46
|
+
> *Project còn ở bố cục phẳng cũ (`bdd/*.feature`): chạy `npx @educa-corp/sdd-framework --migrate-bdd-platform` — dry-run mặc định.*
|
|
42
47
|
|
|
43
48
|
---
|
|
44
49
|
|
|
@@ -68,7 +73,24 @@ BDD là **trái tim của traceability**. Mỗi scenario là một đơn vị h
|
|
|
68
73
|
2. 🛑 **UC decomposition checkpoint** — trình danh sách UC/SC để PO chốt.
|
|
69
74
|
3. PRD lớn → **fan-out**: orchestrator giao mỗi UC cho một sub-agent (`_agent_mode`) sinh song song.
|
|
70
75
|
4. Sinh `.feature` theo `feature.template`, gắn `@trace.*`, dựng Coverage Matrix.
|
|
71
|
-
5.
|
|
76
|
+
5. **Gen lại:** bump `@trace.sc_version` **+0.1 cho từng SC có thân đổi** (xem dưới); SC bị xoá mà **đã có code** → giữ row `.tsv`, đặt `status = ORPHANED` (không xoá row — xoá đi thì code thành vô hình).
|
|
77
|
+
6. Có thể incorporate **scenario proposal** đã `accepted` từ tester — khi chèn phải **normalize**: gán `sc_id` kế tiếp, strip `@proposed`/`@from-test`, append row `.tsv` (xem [Feedback Loop](10-feedback-loop.md)).
|
|
78
|
+
|
|
79
|
+
### `sc_version` — tín hiệu DRIFT duy nhất
|
|
80
|
+
|
|
81
|
+
Mỗi scenario mang `@trace.sc_version` riêng. Nó là **thứ duy nhất** cho `/validate-traces` biết code của SC đó đã lỗi thời (`spec_ver != gen_ver` → `DRIFT`).
|
|
82
|
+
|
|
83
|
+
| Đổi cái gì | Bump? |
|
|
84
|
+
|---|:---:|
|
|
85
|
+
| Tên `Scenario:` · chuỗi step · data table · `# Side-effects:` | ✅ **+0.1** |
|
|
86
|
+
| `@trace.business_rules` · tag `@happy`/`@edge` · comment | ❌ không |
|
|
87
|
+
| Header file · Coverage Matrix · gom NHÓM | ❌ không (đó là `bdd_version`) |
|
|
88
|
+
|
|
89
|
+
**Ai bump:** `/generate-bdd` (khi gen lại, so 4 thành phần trên với bản trên disk) · `/review-context --fix`/`--resume` (mỗi SC có finding đổi thân) · **người sửa tay** (có mục trong Pre-merge Checklist).
|
|
90
|
+
|
|
91
|
+
> Sửa SC mà quên bump → code sinh từ bản cũ **vĩnh viễn hiện `OK`**, không ai biết phải regen. Bump vô cớ thì ngược lại: mọi SC hiện `DRIFT` giả và cờ mất giá trị.
|
|
92
|
+
>
|
|
93
|
+
> Phân biệt với `@trace.bdd_version` (**cấp file**): nó bắt thay đổi mà `sc_version` không thấy — Background, `@trace.dataset`, Business Definition. Cả hai đều cần.
|
|
72
94
|
|
|
73
95
|
**`/review-context` (BDD)** — findings có mã, sạch critical mới `approved`:
|
|
74
96
|
|
|
@@ -74,15 +74,32 @@
|
|
|
74
74
|
|
|
75
75
|
**`/review-tech-docs`** — review **đa chiều**, findings gom theo từng UC (đọc §10 UC Coverage):
|
|
76
76
|
- Kiểm tính đủ/đúng của contract, entity, error, dependency.
|
|
77
|
+
- **T3 — BDD traceability**: design có khớp **nội dung** scenario không (2 chiều, match trong đúng lane platform).
|
|
78
|
+
- **T3b — BDD freshness**: doc này dựng từ BDD **version nào**, BDD giờ ở version nào.
|
|
77
79
|
- **T7 — cổng ký liên team**: contract cross-service phải được các team liên quan **ký** trước khi code.
|
|
78
80
|
|
|
81
|
+
### T3b — vì sao độ tươi cần một cổng riêng
|
|
82
|
+
|
|
83
|
+
Header tech-doc mang `@trace.bdd_versions` — **map theo platform** (`system=1.5, web=1.9`), số nhiều, cố ý khác `@trace.bdd_version` (scalar) của `.feature`. T3b so từng entry với `.feature` tương ứng:
|
|
84
|
+
|
|
85
|
+
| Điều kiện | Severity | Auto-fix? |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `.feature` **mới hơn** map | **Major** | ❌ cần người review lại §4/§4.5 rồi bump `@trace.revision` |
|
|
88
|
+
| Platform có `.feature` nhưng **vắng** trong map | Major | ✅ thêm entry sau khi xác nhận §4 đã phủ |
|
|
89
|
+
| Map có platform mà không còn `.feature` | Minor | ✅ xoá entry |
|
|
90
|
+
|
|
91
|
+
> **Major chứ không Minor** vì `/generate-code` DS3 thấy doc `approved` + 0 blocker-GAP sẽ lấy shape DTO/endpoint/error ở §4 **nguyên văn**. Contract dựng từ BDD cũ lan **thẳng** vào code — tệ hơn drift-về-code vì nó sai từ nguồn.
|
|
92
|
+
>
|
|
93
|
+
> Khi áp fix, **cấm chỉ sửa số trong map** cho ca "`.feature` mới hơn": làm thế là dán nhãn "đã đồng bộ" lên một contract chưa ai review. Platform còn finding `open` thì **giữ số cũ** để cờ `TECHDOC_STALE_VS_BDD` của [`/validate-traces`](09-validate-traces.md) còn sáng.
|
|
94
|
+
|
|
79
95
|
---
|
|
80
96
|
|
|
81
97
|
## HITL / Gate
|
|
82
98
|
|
|
83
99
|
- 🟠 SA duyệt tech-design; **read-only** review — chỉ báo findings, không tự sửa.
|
|
84
100
|
- 🔒 **T7 sign-off**: contract liên team chưa ký → không mở khoá code phía tiêu thụ.
|
|
85
|
-
-
|
|
101
|
+
- 🟡 **T3b (chặn mềm)**: còn finding T3b Major `open` → CHECKPOINT `Y/N` trước khi đặt `approved`. Mềm chứ không cứng như GATE §12 blocker-GAP, vì BDD hay bump vì lý do **không chạm contract** (sửa từ ngữ step) — người review là người biết.
|
|
102
|
+
- `@trace.status: approved` trên tech-design → `/generate-code` dùng §4 làm nguồn contract; `draft/in-review` hoặc còn blocker-GAP → chỉ WARN (không chặn). Tech-doc **cũ hơn BDD** cũng chỉ WARN — nhưng là WARN quan trọng nhất, vì nó xuất hiện đúng lúc shape §4 được lấy nguyên văn.
|
|
86
103
|
|
|
87
104
|
---
|
|
88
105
|
|
|
@@ -37,8 +37,28 @@ Code là **hệ quả của spec, không phải nguồn**. Bước này biến s
|
|
|
37
37
|
|
|
38
38
|
| Artifact | Nội dung |
|
|
39
39
|
|----------|----------|
|
|
40
|
-
| File code | Theo thứ tự layer của stack, tag
|
|
41
|
-
| `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` | Trace row cập nhật: `status`, `implemented_by`, `
|
|
40
|
+
| File code | Theo thứ tự layer của stack, **block 5 tag** ở boundary (dưới) |
|
|
41
|
+
| `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` | Trace row cập nhật: `status`, `implemented_by`, `gen_ver`, `fe_phase`… |
|
|
42
|
+
| `_seams.tsv` | Sổ nợ seam/stub — chỗ chưa implement, để không đẻ mồ côi |
|
|
43
|
+
|
|
44
|
+
### Block 5 tag trên mỗi entry-point
|
|
45
|
+
|
|
46
|
+
```java
|
|
47
|
+
// @trace.implements=AUTH-UC1-SC3
|
|
48
|
+
// @trace.prd_version=1.2
|
|
49
|
+
// @trace.bdd_version=1.4
|
|
50
|
+
// @trace.tech_doc_revision=3
|
|
51
|
+
// @trace.source=specs/auth/login/bdd/system/AUTH-UC1-login.feature
|
|
52
|
+
public TokenDto login(...) { }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
3 tag version không phải trang trí — chúng là nguồn của `PRD_DRIFT` / `BDD_DRIFT` / `TECHDOC_DRIFT` ở [`/validate-traces`](09-validate-traces.md). Thiếu một tag = drift detection **mù ở file đó**, im lặng.
|
|
56
|
+
|
|
57
|
+
> **File phủ nhiều UC → lặp CẢ BLOCK theo từng method.** Không gộp về một header file, không trỏ `@trace.source` vào **thư mục**.
|
|
58
|
+
>
|
|
59
|
+
> Vì sao: 3 tag version là scalar **theo từng UC** — gộp lại thì không diễn đạt được "UC1 ở bdd v1.4, UC3 ở v2.1" → drift báo oan hoặc mù. Và các lệnh tra tag bằng **khớp chuỗi chính xác** (`/dev-gen-test`, `/review-code`, `/validate-traces` đều tìm `@trace.implements={UC-ID}`), nên tag trỏ thư mục ra **0 kết quả** → UC rơi về `UNTRACKED` dù code đã có.
|
|
60
|
+
>
|
|
61
|
+
> Quy tắc EXTEND vốn đã yêu cầu giữ **nguyên si** mọi `@trace.implements` cũ *kể cả của UC khác* — tức thiết kế vốn là **tích luỹ nhiều block**.
|
|
42
62
|
|
|
43
63
|
---
|
|
44
64
|
|
|
@@ -80,8 +100,19 @@ Code là **hệ quả của spec, không phải nguồn**. Bước này biến s
|
|
|
80
100
|
|
|
81
101
|
> Nhánh wire API thật (`integration` / `fe_full`) đi qua **DS4** (kiểm §4.5.4 đủ, vét nguồn rồi gộp-hỏi) và **DS5** (phát hiện component/service FE đang chạy → hỏi reuse/new, không dựng song song). Bảng hành vi đầy đủ từng bước → [Explain · generate-code](../../explain/09-generate-code.md#hành-vi-theo-mode-phase--platform).
|
|
82
102
|
|
|
83
|
-
**`/review-code`** — read-only, chỉ báo findings (không tự sửa: "AI tự fix tự review" = lặp lỗi).
|
|
84
|
-
|
|
103
|
+
**`/review-code`** — read-only, chỉ báo findings (không tự sửa: "AI tự fix tự review" = lặp lỗi). **5 lăng kính:**
|
|
104
|
+
|
|
105
|
+
| # | Lăng kính | Điểm đáng chú ý |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| 1 | Traceability | đủ **4 tag version** kèm mỗi `@trace.implements` · `@trace.source` trỏ file **có thật, đúng platform** · file đa-UC có block riêng theo method · **tag mồ côi** (`TRACE_ORPHAN`) = critical |
|
|
108
|
+
| 2 | Layer Architecture | đúng layer, chiều phụ thuộc, không bypass |
|
|
109
|
+
| 3 | Coding Standards | naming, wrapper, exception, transaction, không magic number |
|
|
110
|
+
| 4 | Spec Compliance | mỗi scenario có implementation, không endpoint không-spec |
|
|
111
|
+
| 5 | **Seam & Stub** | sổ `_seams.tsv` 0 dòng `READY` · stub không còn là binding khi hàng thật đã có · **method thật mồ côi** do đẻ song song |
|
|
112
|
+
|
|
113
|
+
> Critical ở lăng kính 5 → `NEEDS_FIX` **kể cả khi build xanh và test từng-UC xanh** — đó chính là lớp lỗi hai thứ đó không bắt được.
|
|
114
|
+
|
|
115
|
+
**`/fix-bug`** — sửa lỗi có root-cause + regression test, **và cập nhật sổ trace**; xem [Feedback Loop](10-feedback-loop.md).
|
|
85
116
|
|
|
86
117
|
---
|
|
87
118
|
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
# Bước 9 · Validate Traces — Ma trận độ phủ (Coverage Matrix)
|
|
4
4
|
|
|
5
|
-
> **Tóm tắt.** Check
|
|
6
|
-
> **Command:** `/validate-traces`
|
|
5
|
+
> **Tóm tắt.** Check độ phủ giữa **spec ↔ code ↔ test** — 2 chiều quét, **6 tầng drift**, 4 cờ 🔴 chặn PR, 2 cờ ⓘ. Chỉ ra chỗ chưa phủ — mặc định **không sửa gì**.
|
|
6
|
+
> **Command:** `/validate-traces` · `--realign-prd-version {UC-ID}` · `--realign-techdoc-revision {UC-ID}`
|
|
7
|
+
>
|
|
8
|
+
> *Lệnh **read-only** ở chế độ thường. Hai flag `--realign-*` là ngoại lệ có kiểm soát: chúng sửa **đúng dòng `@trace.*`** trong code, không đụng logic — xem [Realign](#realign--đường-ra-cho-cờ-ⓘ).*
|
|
7
9
|
|
|
8
10
|
| | |
|
|
9
11
|
|---|---|
|
|
@@ -19,8 +21,10 @@
|
|
|
19
21
|
|
|
20
22
|
Traceability chỉ có giá trị khi **kiểm được**. Bước này cho một **bức tranh toàn cục**: scenario nào đã có code, có test, hay còn hở — để không "tưởng xong mà chưa xong". Vì là **read-only**, chạy lúc nào cũng an toàn.
|
|
21
23
|
|
|
22
|
-
- Đối chiếu spec ↔ code ↔ test cho từng SC.
|
|
23
|
-
-
|
|
24
|
+
- Đối chiếu spec ↔ code ↔ test cho từng SC (chiều **spec → code**).
|
|
25
|
+
- Quét **chiều ngược** (code → spec): tag trỏ vào scenario **không còn tồn tại**.
|
|
26
|
+
- Phát hiện drift ở **4 tầng**: PRD · BDD · tech-doc → code, và tech-doc lỗi thời so với BDD.
|
|
27
|
+
- Bắt **mồ côi khi ghép luồng** (seam/stub) — lớp lỗi mà build xanh + test từng-UC xanh không thấy.
|
|
24
28
|
- Chỉ ra **gap** chưa phủ để lên kế hoạch bù.
|
|
25
29
|
|
|
26
30
|
---
|
|
@@ -35,7 +39,10 @@ Traceability chỉ có giá trị khi **kiểm được**. Bước này cho mộ
|
|
|
35
39
|
| Artifact | Nội dung |
|
|
36
40
|
|----------|----------|
|
|
37
41
|
| Ma trận coverage spec ↔ code ↔ test | Trạng thái từng SC + `code_coverage` tổng |
|
|
38
|
-
|
|
|
42
|
+
| `{trace_dir}/trace-report.json` | Bản máy đọc cho **panel VS Code** ("Spec Driven Docs Tools") — bị **ghi đè** mỗi lần chạy |
|
|
43
|
+
| `{trace_dir}/trace-history.jsonl` | **Nhật ký append-only** — mỗi lần chạy ghi thêm 1 dòng *delta*. Đây là **dữ liệu**, không phải mirror: **phải commit**, mất là mất vĩnh viễn |
|
|
44
|
+
| Cờ audit | 6 cờ drift + 4 cờ 🔴 chặn PR + 2 cờ ⓘ (bảng dưới) |
|
|
45
|
+
| Hàng đợi | Đếm PRD change request còn `Open` kèm **số ngày chờ** (Step 7b) |
|
|
39
46
|
|
|
40
47
|
---
|
|
41
48
|
|
|
@@ -52,23 +59,124 @@ Traceability chỉ có giá trị khi **kiểm được**. Bước này cho mộ
|
|
|
52
59
|
|
|
53
60
|
- Scenario nào **chưa có code** (UNTRACKED)? Chưa có test (GAP)?
|
|
54
61
|
- Code nào **lỗi thời** so với spec (DRIFT)?
|
|
62
|
+
- Có code nào đang trỏ vào **scenario đã bị xoá** (ORPHANED / TRACE_ORPHAN)?
|
|
63
|
+
- Màn FE nào **demo được nhưng chưa nối backend** (`fe_phase = ui`)?
|
|
64
|
+
- Luồng ghép có chỗ nào chạy vào **no-op** (SEAM_UNWIRED / STUB_UNRESOLVED)?
|
|
55
65
|
- Độ phủ tổng thể (`code_coverage`) bao nhiêu?
|
|
56
66
|
|
|
57
67
|
---
|
|
58
68
|
|
|
59
69
|
## Framework xử lý thế nào (Mechanics)
|
|
60
70
|
|
|
61
|
-
Phân loại
|
|
71
|
+
### Phân loại `status` từng SC (thứ tự ưu tiên, rule sớm thắng)
|
|
62
72
|
|
|
63
73
|
| # | Trạng thái | Điều kiện |
|
|
64
74
|
|---|-----------|-----------|
|
|
65
|
-
|
|
|
75
|
+
| 0 | **ORPHANED** | SC **không còn trong `.feature`** nhưng `implemented_by != —` — code trỏ vào scenario đã bị xoá |
|
|
76
|
+
| 1 | **UNTRACKED** | `implemented_by == —` — scenario chưa từng sinh code |
|
|
66
77
|
| 2 | **DRIFT** | có `implemented_by` **và** `spec_ver != gen_ver` — spec đổi sau codegen → **regen trước khi test** |
|
|
67
78
|
| 3 | **GAP** | có `implemented_by` **và** (`test_count == — / 0`) — có code, chưa test |
|
|
68
79
|
| 4 | **OK** | `spec_ver == gen_ver`, có `implemented_by`, `test_count > 0` |
|
|
69
80
|
|
|
81
|
+
> **Vì sao ORPHANED là Rule 0:** 4 rule kia đều giả định scenario **còn tồn tại** — chúng trả lời *"spec này implement tới đâu"*. `ORPHANED` trả lời câu ngược: *"code này còn spec nào bảo lãnh không"*. Để rule khác thắng thì mỗi giá trị **route người dùng sang một lệnh vô nghĩa**: `GAP` → sinh test cho SC không tồn tại · `DRIFT` → regen từ SC đã xoá · `OK` → cho tạo PR.
|
|
82
|
+
>
|
|
70
83
|
> **Vì sao DRIFT xét trước GAP:** một SC đã có code, chưa test, **và** spec vừa drift phải hiện `DRIFT` (không phải `GAP`) — vì `/generate-code` xử `GAP` = "skip codegen" còn `DRIFT` = "regenerate". Nếu GAP thắng, code lỗi thời bị bỏ qua và test sinh trên code cũ.
|
|
71
84
|
|
|
85
|
+
`code_coverage = (rows where implemented_by != —) / total_scs` — và **`total_scs` loại row `ORPHANED`**: nó không còn là scope, tính vào mẫu số sẽ bóp méo coverage vì một thứ không ai cần implement.
|
|
86
|
+
|
|
87
|
+
### Hai chiều quét
|
|
88
|
+
|
|
89
|
+
| Chiều | Bước | Bắt gì |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| **spec → code** | Step 2 | mỗi row `.tsv` — SC đó implement/test tới đâu |
|
|
92
|
+
| **code → spec** | Step 2b | tag `@trace.implements`/`@trace.verifies` trỏ SC **không tồn tại** |
|
|
93
|
+
|
|
94
|
+
Chiều ngược là cần thiết vì gen lại BDD có thể làm một SC biến mất (gộp / đổi số / xoá) trong khi code implement nó vẫn nằm đó, vẫn được caller gọi. Không có Step 2b thì method đó **vô hình**: không status nào, không report nào — và coverage còn *đẹp hơn* thực tế vì mẫu số nhỏ đi.
|
|
95
|
+
|
|
96
|
+
### Cờ drift — 6 tầng
|
|
97
|
+
|
|
98
|
+
| Cờ | So cái gì | Step |
|
|
99
|
+
|---|---|:---:|
|
|
100
|
+
| `PRD_DRIFT` | Version PRD vs cột `prd_version` vs `@trace.prd_version` trong code — **và** changelog **có** nêu UC này | 4 |
|
|
101
|
+
| `TECHDOC_DRIFT` · `FE_TECHDOC_DRIFT` | `@trace.revision` tech-doc vs cột đã lưu — **và** changelog nêu UC này | 5 |
|
|
102
|
+
| `BDD_DRIFT` | `@trace.bdd_version` trong code vs `.feature` hiện tại | 5c |
|
|
103
|
+
| `TECHDOC_STALE_VS_BDD` | map `@trace.bdd_versions` của tech-doc vs `.feature` hiện tại | 5c |
|
|
104
|
+
| `DESIGNSPEC_DRIFT` | `@trace.design_spec_version` trong code FE vs Version design-spec *(chỉ FE/App)* | 5d |
|
|
105
|
+
| `DESIGNSPEC_STALE_VS_BDD` | cột `design_spec_version` vs Version design-spec — BDD dựng từ bản cũ, **có thể thiếu Screen State / AC-UI vừa thêm** | 5d |
|
|
106
|
+
|
|
107
|
+
**Design-spec vào trace từ v0.4.3.** Trước đó nó là artifact upstream **duy nhất** không có cột TSV, không có tag trong code, không có cờ — dù nó điều khiển **cả** BDD FE/App (Screen States + AC-UI) **lẫn** code FE (màn hình, component inventory, Figma frame). Nó tự bảo vệ **một chiều** (reset `draft` khi PRD đổi); chiều *"designer sửa design-spec **sau khi** BDD/code đã sinh"* thì không gì bắt được.
|
|
108
|
+
|
|
109
|
+
`BDD_DRIFT` **bổ trợ** cho `sc_version`, không thay thế: `sc_version` bắt thay đổi trong **thân scenario**, `bdd_version` bắt thay đổi **cấp file** mà `sc_version` không thấy (Background, `@trace.dataset`, Business Definition, Coverage Matrix).
|
|
110
|
+
|
|
111
|
+
`TECHDOC_STALE_VS_BDD` là ca nguy hiểm nhất trong bảng: `/generate-code` DS3 thấy tech-doc `approved` sẽ lấy shape §4 **nguyên văn** làm contract "đã chốt" — contract dựng từ BDD cũ lan **thẳng** vào code. Cổng chặn nằm ở [`/review-tech-docs` **T3b**](05-tech-docs.md).
|
|
112
|
+
|
|
113
|
+
### 4 cờ 🔴 — chặn PR
|
|
114
|
+
|
|
115
|
+
| Cờ | Nghĩa |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `ORPHANED` | code còn, scenario đã bị xoá khỏi `.feature` (row `.tsv` được giữ lại **chủ động**) |
|
|
118
|
+
| `TRACE_ORPHAN` | tag trỏ SC không tồn tại **và không có row `.tsv`** — nợ cũ, **không chỗ nào khác bắt được** |
|
|
119
|
+
| `SEAM_UNWIRED` | hàng thật đã có nhưng consumer còn wire vào stub → luồng chạy vào no-op |
|
|
120
|
+
| `STUB_UNRESOLVED` | method còn trắng dù owner UC đã gen / đã đẻ hàm song song |
|
|
121
|
+
|
|
122
|
+
> `SEAM_PENDING` / `STUB_PENDING` (owner chưa gen) là **bình thường** — chỉ nhắc.
|
|
123
|
+
>
|
|
124
|
+
|
|
125
|
+
### 2 cờ ⓘ — báo động oan đã được lọc ra
|
|
126
|
+
|
|
127
|
+
| Cờ | Nghĩa | Đường ra |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| `PRD_STALE_REF` | Version PRD lệch **nhưng changelog KHÔNG nêu UC này** → nội dung không đổi, chỉ con trỏ cũ | `--realign-prd-version {UC-ID}` |
|
|
130
|
+
| `TECHDOC_STALE_REF` | Đối xứng, cho tech-doc | `--realign-techdoc-revision {UC-ID}` |
|
|
131
|
+
|
|
132
|
+
**Vì sao cần tách hai cờ này ra.** PRD là tài liệu **cấp feature** phủ nhiều UC, nhưng Version của nó là **một scalar**. Thêm UC7 — không đụng một chữ nào của UC1–UC6 — vẫn làm **cả 6 UC cũ lệch version**. So version thuần thì cả 6 ăn cờ đỏ **oan**.
|
|
133
|
+
|
|
134
|
+
Tệ hơn: **làm theo hướng dẫn cũng không tắt được.** `/generate-bdd` sạch được cột TSV, nhưng tag trong code chỉ `/generate-code` ghi — mà nó thấy row đang `OK` là **skip**. Vòng lặp đóng, và lối ra duy nhất là ép sinh lại code cho hàng loạt UC không hề thay đổi.
|
|
135
|
+
|
|
136
|
+
Bộ lọc đọc **scope của row changelog** (`/refine-prd` Phase 3 và `/extend-prd` bắt buộc ghi UC/AC/BR bị ảnh hưởng — `/generate-bdd` Version Check đã dùng dữ liệu này từ trước). **Row nào mơ hồ → gắn 🟠 cho MỌI UC** — lưới an toàn: mất tính năng *lọc*, không mất tính năng *cảnh báo*.
|
|
137
|
+
|
|
138
|
+
> Đây là bài mà framework **đã giải đúng ở cấp scenario**: `sc_version` chỉ bump khi thân scenario thực sự đổi, vì *"bump vô cớ sẽ tạo DRIFT giả, làm cờ mất giá trị"*. Hai cờ ⓘ là bản tương ứng ở cấp tài liệu.
|
|
139
|
+
|
|
140
|
+
### Realign — đường ra cho cờ ⓘ
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
/validate-traces --realign-prd-version {UC-ID}
|
|
144
|
+
/validate-traces --realign-techdoc-revision {UC-ID}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Cập nhật cột TSV **và** tag trong code lên version hiện tại. **Ba rào an toàn:**
|
|
148
|
+
|
|
149
|
+
1. **Từ chối chạy** nếu UC đang `DRIFT` / `ORPHANED` / bị gắn 🟠 — khi đó nội dung **đổi thật**, dán nhãn lại là **che lỗi**
|
|
150
|
+
2. **Chỉ sửa dòng `@trace.*`** — guard sau-ghi diff lại, lệch là khôi phục file
|
|
151
|
+
3. **In chính xác** file + dòng đã sửa — realign im lặng là realign không kiểm chứng được
|
|
152
|
+
|
|
153
|
+
> Không đụng `dev_selftest`/`qc_status`: tiền đề của realign là **không có logic nào đổi**, nên luật *"làm mất hiệu lực"* không áp.
|
|
154
|
+
|
|
155
|
+
### Nhật ký lịch sử — đo *tốc độ*, không chỉ *trạng thái*
|
|
156
|
+
|
|
157
|
+
`trace-report.json` bị **ghi đè** mỗi lần chạy, và cột `last_updated` chỉ là một ngày bị 8 lệnh cùng ghi đè. Nên framework đo **trạng thái** rất tốt nhưng không đo được **tốc độ**.
|
|
158
|
+
|
|
159
|
+
Step 8c append 1 dòng *delta* vào `{trace_dir}/trace-history.jsonl` mỗi lần chạy — vài trăm byte, rotate theo tháng — rồi in:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
📈 So lần chạy trước (12/08): code +2% · test −1% · DRIFT +3 · UNTRACKED −5
|
|
163
|
+
Đèn mới bật: SEAM_UNWIRED × 1 · Đèn đã tắt: STUB_UNRESOLVED × 2
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Trả lời được: *lệch từ bao giờ · đang lên hay xuống · case này hỏng đi hỏng lại mấy lần · sprint vừa rồi đóng được bao nhiêu.*
|
|
167
|
+
|
|
168
|
+
| Ràng buộc | Vì sao |
|
|
169
|
+
|---|---|
|
|
170
|
+
| Chỉ ghi vào `{trace_dir}`, **không** mirror | Nhân bản dữ liệu tích luỹ ra chỗ sinh-ra = hai lịch sử lệch nhau |
|
|
171
|
+
| **Phải commit** cùng `.tsv` | Là **dữ liệu**, không regenerate được |
|
|
172
|
+
| Không đụng TSV / `trace-report.json` | TSV là bảng **trạng thái** (giữ phẳng); JSON là contract với panel |
|
|
173
|
+
| **Không lệnh nào gác cổng dựa trên nó** | Để **nhìn**, không phải để chặn. Cổng PR vẫn chỉ là 4 cờ 🔴 |
|
|
174
|
+
> **Build xanh, test từng-UC xanh, coverage đẹp — vẫn có thể còn 🔴.** Đó chính là lớp lỗi mà hai thứ kia không bắt được. `ORPHANED`/`TRACE_ORPHAN` **không tự hết**: phải có người quyết định xoá code+test, hay đưa scenario trở lại `.feature`.
|
|
175
|
+
|
|
176
|
+
### Tín hiệu FE còn dùng mock
|
|
177
|
+
|
|
178
|
+
`fe_on_mock` = số SC có `fe_phase = ui` — FE đã có UI nhưng **chưa wire API thật**. Các SC này có thể đang hiện `OK` (có code, có test) nhưng **test chạy trên mock** → đừng coi là xong tính năng. Route: `/generate-code {feature-file} --phase=integration`.
|
|
179
|
+
|
|
72
180
|
---
|
|
73
181
|
|
|
74
182
|
## HITL / Gate
|
|
@@ -81,11 +189,23 @@ Phân loại mỗi SC theo **thứ tự ưu tiên** (rule sớm thắng):
|
|
|
81
189
|
|
|
82
190
|
```
|
|
83
191
|
/validate-traces auth
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
192
|
+
|
|
193
|
+
🔴 GATE — có MỒ CÔI: 1 SEAM_UNWIRED · 0 STUB_UNRESOLVED · 1 ORPHANED · 0 TRACE_ORPHAN
|
|
194
|
+
Build xanh, test từng-UC xanh, coverage đẹp — nhưng luồng ghép chạy vào no-op,
|
|
195
|
+
hoặc code đang trỏ vào scenario đã bị xoá. KHÔNG coi là pass tới khi CẢ BỐN = 0.
|
|
196
|
+
|
|
197
|
+
AUTH-UC1 SC1 OK
|
|
198
|
+
AUTH-UC1 SC2 GAP (có code, chưa test)
|
|
199
|
+
AUTH-UC2 SC1 DRIFT (spec_ver 1.1 ≠ gen_ver 1.0 → regen)
|
|
200
|
+
AUTH-UC2 SC3 UNTRACKED (chưa sinh code)
|
|
201
|
+
AUTH-UC2 SC7 ORPHANED ⚠ đã xoá khỏi spec nhưng code còn
|
|
202
|
+
code_coverage = 7/9 (78%) ← mẫu số KHÔNG tính row ORPHANED
|
|
203
|
+
|
|
204
|
+
BDD Version Drift:
|
|
205
|
+
AUTH-UC1 (web) — code sinh từ BDD v1.4, .feature giờ v1.6 [SC đang DRIFT: SC2]
|
|
206
|
+
|
|
207
|
+
FE còn dùng mock (fe_phase = ui):
|
|
208
|
+
AUTH-UC1 (web) — 3 SC — có test nhưng chạy trên mock, chưa nối API thật
|
|
89
209
|
```
|
|
90
210
|
|
|
91
211
|
---
|
|
@@ -94,11 +214,16 @@ Phân loại mỗi SC theo **thứ tự ưu tiên** (rule sớm thắng):
|
|
|
94
214
|
|
|
95
215
|
- ❌ Coi validate-traces là "chạy xong là fix xong" — nó chỉ báo cáo; hành động ở `/generate-code` (regen DRIFT) và QC (bù GAP).
|
|
96
216
|
- ❌ Bỏ qua DRIFT rồi test trên code cũ.
|
|
217
|
+
- ❌ **Tạo PR khi còn cờ 🔴.** Build xanh không chứng minh luồng ghép chạy đúng.
|
|
218
|
+
- ❌ Coi `fe_phase = ui` là xong vì status đã `OK` — test đang chạy trên mock.
|
|
219
|
+
- ❌ Xoá row `ORPHANED` khỏi `.tsv` cho "sạch bảng" — làm thế là đưa code mồ côi về trạng thái **vô hình**, đúng cái bug mà Rule 0 sinh ra để chống.
|
|
97
220
|
|
|
98
221
|
---
|
|
99
222
|
|
|
100
223
|
## Bước tiếp theo (Next step)
|
|
101
224
|
|
|
225
|
+
**Thứ tự xử lý:** cờ 🔴 trước (chặn PR) → rồi drift → rồi GAP. Route đầy đủ nằm ở bảng "Gợi ý lệnh tiếp theo" cuối report.
|
|
226
|
+
|
|
102
227
|
Gap/drift phát hiện → quay lại `/generate-code` (regen) hoặc bù test; lỗi/thiếu từ QC → vòng phản hồi:
|
|
103
228
|
|
|
104
229
|
➡️ [Bước 10 · Feedback Loop — `/report-bug` · `/propose-scenario` · `/learn` · `/sync`](10-feedback-loop.md)
|