@educa-corp/sdd-framework 0.4.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/build.js +113 -19
- package/bin/gate-trace.js +464 -0
- package/bin/index.js +418 -146
- package/bin/lint-trace.js +602 -0
- package/bin/self-check.js +499 -6
- package/bin/trace-schema.json +1449 -692
- package/commands/debug.md +123 -510
- package/commands/debug.tmpl +3 -0
- package/commands/define-product.md +86 -509
- package/commands/dev-gen-test.md +120 -516
- package/commands/dev-run-test.md +120 -516
- package/commands/dev-smoke-test.md +86 -509
- package/commands/extend-prd.md +486 -0
- package/commands/extend-prd.tmpl +273 -0
- package/commands/fix-bug.md +152 -515
- package/commands/generate-architecture.md +94 -514
- package/commands/generate-architecture.tmpl +3 -0
- package/commands/generate-bdd.md +138 -519
- package/commands/generate-bdd.tmpl +18 -3
- package/commands/generate-code.md +156 -523
- package/commands/generate-code.tmpl +36 -7
- package/commands/generate-design-spec.md +86 -509
- package/commands/generate-prd.md +114 -509
- package/commands/generate-prd.tmpl +28 -0
- package/commands/generate-spec-manifest.md +86 -509
- package/commands/generate-tech-docs.md +86 -509
- package/commands/learn.md +172 -495
- package/commands/learn.tmpl +70 -3
- package/commands/map-testids.md +86 -509
- package/commands/propose-scenario.md +136 -508
- package/commands/propose-scenario.tmpl +52 -1
- package/commands/qc-analyze.md +86 -509
- package/commands/qc-design-test.md +87 -509
- package/commands/qc-design-test.tmpl +1 -0
- package/commands/qc-plan.md +86 -509
- package/commands/qc-report.md +86 -509
- package/commands/qc-review.md +86 -509
- package/commands/qc-run-test.md +133 -517
- package/commands/qc-run-test.tmpl +13 -1
- package/commands/refine-prd.md +99 -519
- package/commands/refine-prd.tmpl +3 -0
- package/commands/report-bug.md +86 -509
- package/commands/review-code.md +127 -513
- package/commands/review-code.tmpl +7 -3
- package/commands/review-context.md +96 -515
- package/commands/review-context.tmpl +6 -2
- package/commands/review-tech-docs.md +90 -510
- package/commands/review-tech-docs.tmpl +3 -0
- package/commands/setup-ai-first.md +166 -137
- package/commands/setup-ai-first.tmpl +72 -0
- package/commands/sync.md +86 -118
- package/commands/sync.tmpl +84 -16
- package/commands/update-framework.md +16 -102
- package/commands/update-framework.tmpl +14 -0
- package/commands/validate-traces.md +458 -531
- package/commands/validate-traces.tmpl +381 -31
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/README.md +20 -0
- package/core/commands/debug.md +123 -510
- package/core/commands/define-product.md +86 -509
- package/core/commands/dev-gen-test.md +120 -516
- package/core/commands/dev-run-test.md +120 -516
- package/core/commands/dev-smoke-test.md +86 -509
- package/core/commands/extend-prd.md +486 -0
- package/core/commands/fix-bug.md +152 -515
- package/core/commands/generate-architecture.md +94 -514
- package/core/commands/generate-bdd.md +138 -519
- package/core/commands/generate-code.md +156 -523
- package/core/commands/generate-design-spec.md +86 -509
- package/core/commands/generate-prd.md +114 -509
- package/core/commands/generate-spec-manifest.md +86 -509
- package/core/commands/generate-tech-docs.md +86 -509
- package/core/commands/learn.md +172 -495
- package/core/commands/map-testids.md +86 -509
- package/core/commands/propose-scenario.md +136 -508
- package/core/commands/qc-analyze.md +86 -509
- package/core/commands/qc-design-test.md +87 -509
- package/core/commands/qc-plan.md +86 -509
- package/core/commands/qc-report.md +86 -509
- package/core/commands/qc-review.md +86 -509
- package/core/commands/qc-run-test.md +133 -517
- package/core/commands/refine-prd.md +99 -519
- package/core/commands/report-bug.md +86 -509
- package/core/commands/review-code.md +127 -513
- package/core/commands/review-context.md +96 -515
- package/core/commands/review-tech-docs.md +90 -510
- package/core/commands/setup-ai-first.md +166 -137
- package/core/commands/sync.md +86 -118
- package/core/commands/update-framework.md +16 -102
- package/core/commands/validate-traces.md +458 -531
- package/core/hooks/data-guard.js +174 -83
- package/core/hooks/settings.json +2 -1
- package/core/rules/workflow.md +48 -4
- package/core/steps/capture-lesson.md +34 -1
- package/core/steps/context-loader.md +24 -3
- package/core/steps/gate.md +92 -35
- package/core/steps/report-footer.md +26 -2
- package/core/steps/trace-mirror.md +34 -7
- package/core/templates/README.md +24 -1
- package/core/templates/ci/trace-gate.yml +146 -0
- package/core/templates/feature.template +1 -1
- package/core/templates/hooks/pre-push +61 -0
- 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 +48 -5
- 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 +183 -117
- package/docs/03-guides/architect.md +63 -0
- 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/model-selection.md +32 -19
- 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 +75 -68
- package/docs/explain/23-fix-bug.md +19 -3
- package/docs/explain/26-propose-scenario.md +70 -63
- package/docs/explain/27-learn.md +5 -3
- package/docs/explain/README.md +135 -134
- package/hooks/data-guard.js +174 -83
- package/hooks/settings.json +2 -1
- package/package.json +53 -50
- package/rules/workflow.md +48 -4
- package/steps/capture-lesson.md +34 -1
- package/steps/context-loader.md +24 -3
- package/steps/gate.md +92 -35
- package/steps/report-footer.md +26 -2
- package/steps/trace-mirror.md +34 -7
- package/templates/README.md +24 -1
- package/templates/ci/trace-gate.yml +146 -0
- package/templates/feature.template +1 -1
- package/templates/hooks/pre-push +61 -0
- package/scripts/init.sh +0 -49
- package/scripts/upgrade.sh +0 -94
|
@@ -61,14 +61,57 @@ Spec-driven thành/bại phụ thuộc **~80%** vào việc context được n
|
|
|
61
61
|
## Template Pipeline
|
|
62
62
|
|
|
63
63
|
```
|
|
64
|
-
.tmpl
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
.agent/commands/*.md (runtime)
|
|
64
|
+
.tmpl + steps/*.md ──build──► commands/*.md ──► core/* ──► .agent/ 904 KB
|
|
65
|
+
│ ▲
|
|
66
|
+
bin/self-check.js (fail build) --init cài vào đây
|
|
68
67
|
```
|
|
69
68
|
|
|
70
|
-
|
|
69
|
+
**Vì sao slim (G45):** build inline `{{include:}}` vào **từng** file lệnh. Với 32 lệnh, kết quả là
|
|
70
|
+
2069 KB mà chỉ 580 KB là nội dung riêng của chúng — **72% là vài step giống hệt nhau, chép 30 lần**.
|
|
71
|
+
`/generate-code` từng nặng 108 KB (≈27k token đọc **trước** khi làm gì), gần một nửa không nói gì về
|
|
72
|
+
việc sinh code. Cái giá thật không phải tiền: trên PRD nhiều UC nó làm tăng rủi ro **cạn context
|
|
73
|
+
giữa lúc ghi sổ trace**.
|
|
74
|
+
|
|
75
|
+
| Step | Xử lý trong `core/` | Vì sao |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `context-loader.md` (33 K × 29) | **đọc lúc chạy** | 64% lãng phí. Bỏ sót ⇒ lệnh **dừng ngay** vì thiếu path/config — hỏng ồn ào |
|
|
78
|
+
| `report-footer.md` (7 K × 32) | **đọc lúc chạy** | 16%. Bỏ sót ⇒ report kém cấu trúc, không hỏng gì |
|
|
79
|
+
| `gate.md` (7 K × 30) | **giữ inline** | Chỉ 15%, nhưng là **lưới an toàn** (model check · resolve target · CHECKPOINT). Bỏ sót ⇒ lệnh **vẫn chạy** mà không còn cổng nào — hỏng **âm thầm** |
|
|
80
|
+
|
|
81
|
+
Kết quả: `/generate-code` 108 KB → **69 KB**, `/refine-prd` 85 KB → **45 KB**.
|
|
82
|
+
|
|
83
|
+
> **Một biến thể duy nhất.** Bản đầu của G45 phải build **hai** bản: `commands/*.md` inline đầy đủ
|
|
84
|
+
> cho legacy mode (`--project` / không cờ) — vì nó copy thẳng file đó vào `.claude/commands/` mà
|
|
85
|
+
> **không** cài `.agent/`, nên không có `.agent/steps/` để đọc — và bản slim cho `--init`.
|
|
86
|
+
> **G50 gỡ hẳn legacy mode**, nên giờ mọi bản cài đều có `.agent/steps/` và nhánh build thứ hai
|
|
87
|
+
> biến mất. Hai nhánh build gần giống nhau là nợ chờ lệch.
|
|
88
|
+
|
|
89
|
+
- Cơ chế `{{include:steps/...}}` → single source of truth ở `.tmpl` + `steps/`.
|
|
71
90
|
- **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.)*
|
|
91
|
+
- **Sửa `steps/context-loader.md` hay `report-footer.md` giờ có hiệu lực NGAY** ở project đã cài — chúng được đọc lúc chạy, không còn phải build + publish + `/update-framework`.
|
|
92
|
+
- **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.
|
|
93
|
+
|
|
94
|
+
### Self-check — contract trace không được lệch
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
bin/trace-schema.json ──[bin/self-check.js]──> đối chiếu commands/*.tmpl + steps/*.md
|
|
98
|
+
(SoT máy đọc) → exit 1 nếu lệch → build FAIL
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**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.
|
|
102
|
+
|
|
103
|
+
| Rule | Bắt gì | Mức |
|
|
104
|
+
|:---:|---|:---:|
|
|
105
|
+
| R1 | field có consumer nhưng **không producer** | ERROR |
|
|
106
|
+
| R2 | field có producer nhưng **không ai đọc** (field chết) | WARN |
|
|
107
|
+
| R3 | actor khai trong schema mà file của nó **không nhắc** field | ERROR |
|
|
108
|
+
| R4 | `{paths.X}` dùng mà không khai / khai mà không ai dùng | ERROR / WARN |
|
|
109
|
+
| R5 | pattern bị cấm **quay lại** (vd `bdd/` thiếu `{platform}`) | ERROR |
|
|
110
|
+
| R6 | giá trị enum khai mà **không xuất hiện ở đâu** | WARN |
|
|
111
|
+
|
|
112
|
+
**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`.
|
|
113
|
+
|
|
114
|
+
*(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
115
|
|
|
73
116
|
---
|
|
74
117
|
|
|
@@ -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)
|
|
@@ -32,11 +32,25 @@ Framework là pipeline **một chiều** — nhưng vẫn cần đường **ph
|
|
|
32
32
|
| Lệnh | Ai dùng | Kết quả | Đi về đâu |
|
|
33
33
|
|------|---------|---------|-----------|
|
|
34
34
|
| `/report-bug` | Tester / QC | Bug **spec-anchored** (gồm product-gap từ `/qc-*`) | `feedback/bug-reports/` |
|
|
35
|
-
| `/propose-scenario` | Tester / QC |
|
|
35
|
+
| `/propose-scenario` **Case A** | Tester / QC | Thiếu scenario cho **AC đã có** | `feedback/bdd-proposals/` |
|
|
36
|
+
| `/propose-scenario` **Case B** | Tester / QC | **Requirement MỚI** — không AC nào phủ | `feedback/prd-change-requests/` |
|
|
36
37
|
| `/learn` | Tất cả | Guardrail lesson | `project-lessons.md` (qua step `capture-lesson`) |
|
|
37
38
|
| `/fix-bug` | Dev | Sửa lỗi có root-cause + regression test | Code + `@trace.fixes/root_cause/regression` |
|
|
39
|
+
| `/extend-prd` | PO | **Drain** PRD change request → UC/AC/BR mới trong PRD | PRD v+1 · request → `archived/` |
|
|
38
40
|
| `/sync` | Lead (umbrella) | Pull + submodule + **nổi feedback** + làm mới Living Docs | Chạy hằng ngày |
|
|
39
41
|
|
|
42
|
+
### Ba hàng đợi — mỗi cái phải có người lấy ra
|
|
43
|
+
|
|
44
|
+
| Hàng đợi | Ai bỏ vào | Ai **lấy ra** | Ai **nhắc lại** |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| `bug-reports/` | `/report-bug` | `/fix-bug` (quét thư mục mỗi lần chạy) | cột `qc_blocked_by` của TSV |
|
|
47
|
+
| `bdd-proposals/` | `/propose-scenario` A | `/generate-bdd` (quét mỗi lần chạy, 9 bước: chèn → normalize → append row TSV → archive → commit) | — |
|
|
48
|
+
| `prd-change-requests/` | `/propose-scenario` B | **`/extend-prd`** | `/validate-traces` Step 7b — đếm `Status: Open` kèm **số ngày chờ** |
|
|
49
|
+
|
|
50
|
+
> **Vì sao cột "ai nhắc lại" quan trọng.** `/sync` chỉ hiện những gì về **trong đúng lần pull đó** (`git diff old..new`) — nó là **chuông cửa, không phải tồn kho**. Bỏ lỡ một lần là mất khỏi màn hình vĩnh viễn. Hai hàng đợi đầu không sao vì có lệnh **quét lại thư mục mỗi lần chạy**; riêng `prd-change-requests/` thì không — nên `/validate-traces` phải nhắc thay.
|
|
51
|
+
>
|
|
52
|
+
> Trước v0.4.3, hàng đợi thứ ba **không có người lấy ra**: có producer, có storage, có commit, có mặt trong `/sync` — nhưng 0 consumer, và **không gì báo**. Yêu cầu nghiệp vụ thật do tester phát hiện từ sản phẩm chạy thật rơi vào im lặng hoàn toàn. Từ v0.4.3, cả ba hàng đợi được khai vào `bin/trace-schema.json` §`queues` nên **self-check chặn build** nếu một hàng đợi mất consumer.
|
|
53
|
+
|
|
40
54
|
---
|
|
41
55
|
|
|
42
56
|
## Ai làm gì (Roles & responsibilities)
|
|
@@ -64,10 +78,47 @@ Framework là pipeline **một chiều** — nhưng vẫn cần đường **ph
|
|
|
64
78
|
|
|
65
79
|
1. **`/report-bug` / `/propose-scenario`** — ghi feedback kèm tham chiếu spec vào `feedback/` (spec repo nếu umbrella).
|
|
66
80
|
2. **`/learn`** — qua step `capture-lesson`, ghi guardrail vào `project-lessons.md`; các workflow sau **nạp lại** vào context → hệ thống *nhớ*.
|
|
67
|
-
3. **`/generate-bdd`** —
|
|
68
|
-
|
|
81
|
+
3. **`/generate-bdd`** — incorporate scenario proposal đã `accepted`, kèm **normalize** (xem dưới).
|
|
82
|
+
3b. **`/extend-prd`** — nhặt PRD change request `accepted` làm **nguyên liệu** (không chèn thẳng: yêu cầu nghiệp vụ phải qua PO chốt AC/BR đúng tầng) → discovery delta + **kiểm va chạm** với UC/BR đã có → đánh số **nối tiếp** → ghi **add-only** + guard sau-ghi → bump version + changelog nêu rõ scope → đóng dấu `incorporated` + `archived/` + commit.
|
|
83
|
+
4. **`/fix-bug`** — đọc bug spec-anchored → branch `fix/{TICKET}-<slug>` → root cause → sửa (tag `@trace.fixes/root_cause/regression`) → regression test + build verify → **cập nhật sổ trace** → commit sau khi user duyệt.
|
|
69
84
|
5. **`/sync`** — pull, init submodule, **nổi feedback** lên PO/Dev, bootstrap config service, làm mới Living Docs. An toàn chạy lặp lại.
|
|
70
85
|
|
|
86
|
+
### Vòng đời bug — mỗi bước có đúng một chủ
|
|
87
|
+
|
|
88
|
+
| State | Ai đặt | Khi nào |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| `🟢 Open` | `/report-bug` | tester/QC file bug |
|
|
91
|
+
| `🟡 Fixed` | `/fix-bug` Phase 5.5 | fix đã commit + push |
|
|
92
|
+
| `🟢 Closed` | **`/qc-run-test`** | QC chạy lại và `qc_status` của SC liên kết flip `pass` |
|
|
93
|
+
|
|
94
|
+
> **Dev không tự đóng bug của mình** — QC sở hữu verification. `/qc-run-test` đọc `qc_blocked_by` **trước** khi clear nó (cột đó chính là con trỏ tới bug; clear xong là mất đường về).
|
|
95
|
+
>
|
|
96
|
+
> Ngoại lệ có chủ đích: SC pass mà bug còn `🟢 Open` (chưa ai fix) → **không đóng**, giữ `Open` + cảnh báo kiểm tra lại test. Test pass trên bug chưa fix là dấu hiệu **test sai**, không phải bug hết — tự đóng ở đây sẽ chôn một defect thật.
|
|
97
|
+
|
|
98
|
+
### `/fix-bug` ghi gì vào sổ trace
|
|
99
|
+
|
|
100
|
+
Regression test không phải test "ngoài luồng" — nó phải hiện lên coverage:
|
|
101
|
+
|
|
102
|
+
| Cột | Ghi gì |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `test_count` | **+=** số test regression (cộng dồn, không ghi đè) |
|
|
105
|
+
| `test_classes` | **append** tên class mới |
|
|
106
|
+
| `dev_selftest` → `not_run` · `dev_selftest_at` → `—` | code vừa đổi nên tín hiệu self-test cũ hết hiệu lực |
|
|
107
|
+
|
|
108
|
+
**Không** đụng `qc_*` (QC sở hữu) và **không** đụng `spec_ver`/`gen_ver` — fix bug không đổi spec, đụng vào là tạo `DRIFT` giả. Next của `/fix-bug` là `/dev-run-test` để lấy lại tín hiệu xanh, rồi mới tạo PR.
|
|
109
|
+
|
|
110
|
+
### Proposal của tester — normalize khi chèn
|
|
111
|
+
|
|
112
|
+
`/propose-scenario` viết scenario theo **đúng** bộ tag canonical (`@trace.scenario` với placeholder `SC?` · `@trace.sc_version: 1.0` · `@trace.business_rules`; AC ghi thành comment `# Covers:` chứ **không** phải trace key). Khi `/generate-bdd` chèn proposal `accepted`, nó phải:
|
|
113
|
+
|
|
114
|
+
1. gán `sc_id` = số SC **kế tiếp** trong file (thay `SC?`)
|
|
115
|
+
2. bổ sung `@trace.business_rules` nếu proposal để `—`
|
|
116
|
+
3. **strip** `@proposed` / `@from-test` — nhãn vòng đời proposal, không thuộc BDD canonical
|
|
117
|
+
4. đặt scenario vào **đúng NHÓM** theo business theme
|
|
118
|
+
5. **append row `.tsv`** (`spec_ver = 1.0`, `status = UNTRACKED`)
|
|
119
|
+
|
|
120
|
+
> Thiếu bước 1/5 thì scenario vào file mà **không có row trace** → vô hình với toàn bộ coverage và drift.
|
|
121
|
+
|
|
71
122
|
---
|
|
72
123
|
|
|
73
124
|
## HITL / Gate
|
|
@@ -86,6 +137,11 @@ QC phát hiện: link reset vẫn dùng được sau khi đổi mật khẩu
|
|
|
86
137
|
/fix-bug BUG-217 → branch fix/BUG-217-invalidate-link
|
|
87
138
|
→ root cause: thiếu invalidate token
|
|
88
139
|
→ fix + regression test + build ✅
|
|
140
|
+
→ trace: test_count +2, dev_selftest → not_run
|
|
141
|
+
→ BUG-217 State: 🟡 Fixed
|
|
142
|
+
/dev-run-test AUTH-UC2 → dev_selftest → pass
|
|
143
|
+
/qc-run-test AUTH-UC2 → qc_status SC1 → pass
|
|
144
|
+
→ BUG-217 State: 🟢 Closed (verified)
|
|
89
145
|
/learn "luôn invalidate one-time token sau khi dùng"
|
|
90
146
|
→ project-lessons.md (nạp lại lần sau)
|
|
91
147
|
```
|
|
@@ -70,4 +70,4 @@ QC █████ 🟠 cổng review test & script
|
|
|
70
70
|
|
|
71
71
|
## Đọc theo vai trò của bạn (Role Guides)
|
|
72
72
|
|
|
73
|
-
→ [Product Owner](
|
|
73
|
+
→ [Product Owner](../03-guides/product-owner.md) · [Developer](../03-guides/developer.md) · [Architect](../03-guides/architect.md) · [Tester/QA](../03-guides/tester-qa.md)
|