@educa-corp/sdd-framework 0.5.0 → 0.7.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 +487 -0
- package/bin/index.js +445 -146
- package/bin/lint-trace.js +643 -0
- package/bin/self-check.js +804 -2
- package/bin/trace-schema.json +621 -10
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/README.md +20 -0
- package/core/commands/amend-prd.md +518 -0
- package/core/commands/debug.md +123 -511
- package/core/commands/define-product.md +86 -510
- package/core/commands/dev-gen-test.md +86 -510
- package/core/commands/dev-run-test.md +133 -519
- package/core/commands/dev-smoke-test.md +86 -510
- package/core/commands/extend-prd.md +128 -522
- package/core/commands/fix-bug.md +118 -509
- package/core/commands/generate-architecture.md +94 -515
- package/core/commands/generate-bdd.md +128 -513
- package/core/commands/generate-code.md +119 -510
- package/core/commands/generate-design-spec.md +86 -510
- package/core/commands/generate-prd.md +89 -510
- package/core/commands/generate-spec-manifest.md +86 -510
- package/core/commands/generate-tech-docs.md +120 -512
- package/core/commands/learn.md +172 -496
- package/core/commands/map-testids.md +86 -510
- package/core/commands/propose-scenario.md +86 -510
- package/core/commands/qc-analyze.md +86 -510
- package/core/commands/qc-design-test.md +86 -510
- package/core/commands/qc-plan.md +86 -510
- package/core/commands/qc-report.md +86 -510
- package/core/commands/qc-review.md +86 -510
- package/core/commands/qc-run-test.md +115 -513
- package/core/commands/refine-prd.md +112 -522
- package/core/commands/report-bug.md +86 -510
- package/core/commands/review-code.md +123 -511
- package/core/commands/review-context.md +136 -522
- package/core/commands/review-tech-docs.md +90 -511
- package/core/commands/setup-ai-first.md +166 -138
- package/core/commands/sync.md +155 -107
- package/core/commands/update-framework.md +16 -103
- package/core/commands/validate-traces.md +426 -511
- package/core/hooks/data-guard.js +174 -83
- package/core/hooks/settings.json +2 -1
- package/core/rules/workflow.md +64 -4
- package/core/steps/capture-lesson.md +34 -1
- package/core/steps/context-loader.md +50 -8
- package/core/steps/gate.md +92 -35
- package/core/steps/report-footer.md +23 -0
- 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/02-concepts/architecture.md +61 -6
- package/docs/02-concepts/traceability.md +57 -0
- package/docs/03-guides/architect.md +63 -0
- package/docs/04-reference/commands.md +148 -134
- package/docs/04-reference/model-selection.md +32 -19
- package/docs/04-reference/trace-schema.md +39 -0
- package/docs/explain/02b-extend-prd.md +1 -1
- package/docs/explain/02c-amend-prd.md +152 -0
- package/docs/explain/21-validate-traces.md +2 -1
- package/docs/explain/27-learn.md +5 -3
- package/docs/explain/28-sync.md +25 -0
- package/docs/explain/README.md +136 -135
- package/package.json +5 -9
- package/commands/debug.md +0 -917
- package/commands/debug.tmpl +0 -257
- package/commands/define-product.md +0 -862
- package/commands/define-product.tmpl +0 -225
- package/commands/dev-gen-test.md +0 -1124
- package/commands/dev-gen-test.tmpl +0 -490
- package/commands/dev-run-test.md +0 -859
- package/commands/dev-run-test.tmpl +0 -225
- package/commands/dev-smoke-test.md +0 -798
- package/commands/dev-smoke-test.tmpl +0 -217
- package/commands/extend-prd.md +0 -907
- package/commands/extend-prd.tmpl +0 -270
- package/commands/fix-bug.md +0 -910
- package/commands/fix-bug.tmpl +0 -197
- package/commands/generate-architecture.md +0 -775
- package/commands/generate-architecture.tmpl +0 -194
- package/commands/generate-bdd.md +0 -1347
- package/commands/generate-bdd.tmpl +0 -590
- package/commands/generate-code.md +0 -1283
- package/commands/generate-code.tmpl +0 -649
- package/commands/generate-design-spec.md +0 -1161
- package/commands/generate-design-spec.tmpl +0 -524
- package/commands/generate-prd.md +0 -1143
- package/commands/generate-prd.tmpl +0 -223
- package/commands/generate-spec-manifest.md +0 -745
- package/commands/generate-spec-manifest.tmpl +0 -164
- package/commands/generate-tech-docs.md +0 -1344
- package/commands/generate-tech-docs.tmpl +0 -273
- package/commands/learn.md +0 -723
- package/commands/learn.tmpl +0 -63
- package/commands/map-testids.md +0 -662
- package/commands/map-testids.tmpl +0 -81
- package/commands/propose-scenario.md +0 -783
- package/commands/propose-scenario.tmpl +0 -202
- package/commands/qc-analyze.md +0 -693
- package/commands/qc-analyze.tmpl +0 -112
- package/commands/qc-design-test.md +0 -650
- package/commands/qc-design-test.tmpl +0 -69
- package/commands/qc-plan.md +0 -630
- package/commands/qc-plan.tmpl +0 -49
- package/commands/qc-report.md +0 -641
- package/commands/qc-report.tmpl +0 -60
- package/commands/qc-review.md +0 -634
- package/commands/qc-review.tmpl +0 -53
- package/commands/qc-run-test.md +0 -750
- package/commands/qc-run-test.tmpl +0 -116
- package/commands/refine-prd.md +0 -1074
- package/commands/refine-prd.tmpl +0 -278
- package/commands/report-bug.md +0 -729
- package/commands/report-bug.tmpl +0 -148
- package/commands/review-code.md +0 -803
- package/commands/review-code.tmpl +0 -143
- package/commands/review-context.md +0 -1323
- package/commands/review-context.tmpl +0 -527
- package/commands/review-tech-docs.md +0 -982
- package/commands/review-tech-docs.tmpl +0 -401
- package/commands/setup-ai-first.md +0 -574
- package/commands/setup-ai-first.tmpl +0 -378
- package/commands/sync.md +0 -486
- package/commands/sync.tmpl +0 -384
- package/commands/update-framework.md +0 -290
- package/commands/update-framework.tmpl +0 -188
- package/commands/validate-traces.md +0 -1435
- package/commands/validate-traces.tmpl +0 -854
- package/hooks/data-guard.js +0 -141
- package/hooks/settings.json +0 -18
- package/modules/android-compose/module.yaml +0 -13
- package/modules/android-compose/stack-profile.yaml +0 -57
- package/modules/angular/architecture-snippets/component-patterns.md +0 -187
- package/modules/angular/module.yaml +0 -6
- package/modules/angular/stack-profile.yaml +0 -38
- package/modules/context-engineering/architecture-snippets/context-design.md +0 -119
- package/modules/context-engineering/module.yaml +0 -9
- package/modules/context-engineering/stack-profile.yaml +0 -61
- package/modules/dotnet/architecture-snippets/clean-arch.md +0 -160
- package/modules/dotnet/module.yaml +0 -6
- package/modules/dotnet/stack-profile.yaml +0 -50
- package/modules/flutter/module.yaml +0 -14
- package/modules/flutter/stack-profile.yaml +0 -59
- package/modules/golang/architecture-snippets/domain-layout.md +0 -283
- package/modules/golang/module.yaml +0 -6
- package/modules/golang/stack-profile.yaml +0 -40
- package/modules/ios-swiftui/module.yaml +0 -13
- package/modules/ios-swiftui/stack-profile.yaml +0 -55
- package/modules/java-spring/architecture-snippets/layered-arch.md +0 -201
- package/modules/java-spring/module.yaml +0 -15
- package/modules/java-spring/stack-profile.yaml +0 -28
- package/modules/nextjs/architecture-snippets/app-router-patterns.md +0 -269
- package/modules/nextjs/module.yaml +0 -14
- package/modules/nextjs/stack-profile.yaml +0 -74
- package/modules/nuxt/module.yaml +0 -14
- package/modules/nuxt/stack-profile.yaml +0 -58
- package/modules/phaser-game/architecture-snippets/phaser-scene-patterns.md +0 -646
- package/modules/phaser-game/module.yaml +0 -15
- package/modules/phaser-game/stack-profile.yaml +0 -90
- package/modules/php-laravel/architecture-snippets/service-repository.md +0 -302
- package/modules/php-laravel/module.yaml +0 -15
- package/modules/php-laravel/stack-profile.yaml +0 -56
- package/modules/qc-playwright/stack-profile.yaml +0 -66
- package/modules/react/architecture-snippets/hooks-query-patterns.md +0 -254
- package/modules/react/module.yaml +0 -14
- package/modules/react/stack-profile.yaml +0 -63
- package/modules/react-native/module.yaml +0 -14
- package/modules/react-native/stack-profile.yaml +0 -56
- package/modules/vue/module.yaml +0 -14
- package/modules/vue/stack-profile.yaml +0 -65
- package/rules/data-protection.md +0 -80
- package/rules/workflow.md +0 -73
- package/scripts/init.sh +0 -49
- package/scripts/upgrade.sh +0 -94
- package/skills/code/SKILL.md +0 -19
- package/skills/code/SKILL.tmpl +0 -19
- package/skills/debug/SKILL.md +0 -19
- package/skills/debug/SKILL.tmpl +0 -19
- package/skills/design-spec/SKILL.md +0 -11
- package/skills/design-spec/SKILL.tmpl +0 -11
- package/skills/discovery/SKILL.md +0 -14
- package/skills/discovery/SKILL.tmpl +0 -14
- package/skills/prd/SKILL.md +0 -19
- package/skills/prd/SKILL.tmpl +0 -19
- package/skills/qc/qa-analyst/DOC_GAPS.template.md +0 -63
- package/skills/qc/qa-analyst/acceptance-criteria.md +0 -60
- package/skills/qc/qa-analyst/business-rules.md +0 -59
- package/skills/qc/qa-analyst/data-flow.md +0 -64
- package/skills/qc/qa-analyst/spec-breakdown.md +0 -61
- package/skills/qc/qa-designer/e2e/journey.md +0 -41
- package/skills/qc/qa-designer/exploratory/charter.md +0 -68
- package/skills/qc/qa-designer/exploratory/explore-to-functional.md +0 -43
- package/skills/qc/qa-designer/functional/api.md +0 -45
- package/skills/qc/qa-designer/functional/gui-feature.md +0 -46
- package/skills/qc/qa-designer/functional/gui-screen.md +0 -52
- package/skills/qc/qa-designer/integration/api.md +0 -42
- package/skills/qc/qa-designer/integration/db.md +0 -39
- package/skills/qc/qa-designer/integration/gui.md +0 -40
- package/skills/qc/qa-designer/integration/kafka.md +0 -40
- package/skills/qc/qa-designer/non-functional.md +0 -40
- package/skills/qc/qa-planner/test-plan.md +0 -120
- package/skills/qc/qa-reviewer/script/e2e.md +0 -87
- package/skills/qc/qa-reviewer/script/exploratory.md +0 -45
- package/skills/qc/qa-reviewer/script/functional.md +0 -101
- package/skills/qc/qa-reviewer/script/integration.md +0 -91
- package/skills/qc/qa-reviewer/script/non-functional.md +0 -126
- package/skills/qc/qa-reviewer/test-case/e2e.md +0 -73
- package/skills/qc/qa-reviewer/test-case/exploratory.md +0 -43
- package/skills/qc/qa-reviewer/test-case/functional.md +0 -76
- package/skills/qc/qa-reviewer/test-case/integration.md +0 -69
- package/skills/qc/qa-reviewer/test-case/non-functional.md +0 -73
- package/skills/qc/qa-runner/e2e.md +0 -49
- package/skills/qc/qa-runner/exploratory/session.md +0 -36
- package/skills/qc/qa-runner/functional/api.md +0 -35
- package/skills/qc/qa-runner/functional/gui-feature.md +0 -51
- package/skills/qc/qa-runner/functional/gui-screen.md +0 -55
- package/skills/qc/qa-runner/integration.md +0 -47
- package/skills/qc/qa-runner/non-functional.md +0 -49
- package/skills/qc/qa-runner/report/report.md +0 -37
- package/skills/setup-ai-first/SKILL.md +0 -19
- package/skills/setup-ai-first/SKILL.tmpl +0 -19
- package/skills/spec/SKILL.md +0 -19
- package/skills/spec/SKILL.tmpl +0 -19
- package/skills/test/SKILL.md +0 -18
- package/skills/test/SKILL.tmpl +0 -18
- package/steps/business-language.md +0 -56
- package/steps/capture-lesson.md +0 -79
- package/steps/context-loader.md +0 -385
- package/steps/gate.md +0 -94
- package/steps/report-footer.md +0 -102
- package/steps/review-fanout.md +0 -159
- package/steps/spawn-agent.md +0 -129
- package/steps/trace-mirror.md +0 -53
- package/templates/README.md +0 -47
- package/templates/architecture.template.md +0 -394
- package/templates/design-spec.template.md +0 -217
- package/templates/feature.template +0 -123
- package/templates/platform-guide.template.md +0 -145
- package/templates/prd.template.md +0 -283
- package/templates/product-definition.template.md +0 -188
- package/templates/project-context.yaml +0 -212
- package/templates/tech-design.template.md +0 -490
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
Check read-only độ phủ giữa spec, code, và test — gồm cả PRD version drift.
|
|
4
4
|
|
|
5
5
|
## Gate
|
|
6
|
+
|
|
7
|
+
*Checkpoint: **không chặn** — read-only (ghi trace-report.json + TSV status, không đụng spec/code). Gate Bước 3 bỏ qua CHECKPOINT (Bước 3a).*
|
|
8
|
+
|
|
6
9
|
# Gate — Quy trình vào chuẩn cho mọi lệnh
|
|
7
10
|
|
|
8
11
|
Mọi lệnh PHẢI chạy gate này trước khi thực thi phần logic riêng của nó.
|
|
@@ -22,35 +25,31 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
|
|
|
22
25
|
- Đi thẳng tới phần logic riêng của lệnh.
|
|
23
26
|
3. Nếu `$ARGUMENTS` không phải JSON hoặc không có `_agent_mode` → tiếp tục sang Bước 1 (chế độ thường).
|
|
24
27
|
|
|
25
|
-
## Bước 0-B —
|
|
28
|
+
## Bước 0-B — Ghi nhận Model *(KHÔNG chặn)*
|
|
26
29
|
|
|
27
|
-
*Bỏ qua
|
|
30
|
+
*Bỏ qua nếu `_agent_mode: true` (sub-agent — orchestrator đã ghi nhận rồi).*
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
Ghi lại **model mà bạn — agent đang chạy lệnh này — thực sự đang dùng**, rồi mang nó vào
|
|
33
|
+
dòng `Model:` của report cuối (xem `report-footer`). Nếu bạn biết mình **không** phải một
|
|
34
|
+
model Opus, gắn thêm cảnh báo ngay ở dòng đó.
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
**KHÔNG hỏi người dùng. KHÔNG chờ. KHÔNG dừng.**
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
Y — đúng → tiếp tục
|
|
47
|
-
S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
|
|
48
|
-
──────────────────────────────────────────────────────────────────
|
|
49
|
-
```
|
|
38
|
+
> **Vì sao bước này từng là prompt chặn, và vì sao bỏ (GAPS-v3 G41):** bản cũ hiện khối
|
|
39
|
+
> `⚙️ MODEL CHECK` rồi chờ `Y/S/N`. Ba vấn đề cùng chỉ một hướng:
|
|
40
|
+
> **(1)** nó hỏi người dùng thứ mà **agent đã biết chính xác**;
|
|
41
|
+
> **(2)** câu trả lời **không kiểm chứng được** — gõ `Y` xong vẫn đang chạy Haiku thì không
|
|
42
|
+
> gì phát hiện;
|
|
43
|
+
> **(3)** **cả `Y` lẫn `S` đều đi tiếp** — cách duy nhất để nó dừng là tự nguyện gõ `N`.
|
|
44
|
+
> Tức nó **không chặn được ai**, mà tốn một lần chặn ở **mọi** lệnh. Một feature đi hết
|
|
45
|
+
> pipeline dùng 20 lệnh; 30/32 lệnh chạy gate. Hai mươi lần bấm cho một tín hiệu tự-khai
|
|
46
|
+
> không kiểm chứng được — và chính cái giá đó làm mòn CHECKPOINT ở Bước 3, cổng có giá trị thật.
|
|
47
|
+
>
|
|
48
|
+
> Khai báo trong report **mạnh hơn** hỏi: đúng nguồn (agent, không phải người), và nằm
|
|
49
|
+
> **cạnh kết quả** để cân nhắc, thay vì nằm trước khi có kết quả để bấm cho xong.
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang một model Opus (`/model`) rồi chạy lại lệnh này."
|
|
51
|
+
**Vẫn khuyến nghị Opus:** phân tích spec, review kiến trúc và sinh code đòi hỏi suy luận sâu;
|
|
52
|
+
model nhỏ hơn dễ bỏ sót edge case và vi phạm kiến trúc. Đổi: `/model` → chọn Opus.
|
|
54
53
|
|
|
55
54
|
## Bước 1 — Xác định Target File
|
|
56
55
|
|
|
@@ -80,419 +79,154 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
|
|
|
80
79
|
|
|
81
80
|
## Bước 3 — CHECKPOINT
|
|
82
81
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
CHECKPOINT
|
|
87
|
-
-----------
|
|
88
|
-
Target : {resolved file path}
|
|
89
|
-
Project : {project.name từ project-context.yaml}
|
|
90
|
-
Tech stack : {language} / {framework}
|
|
91
|
-
Module : {module nếu có, else "not configured"}
|
|
92
|
-
Domains : {danh sách domain, ngăn cách bởi dấu phẩy}
|
|
93
|
-
|
|
94
|
-
Tiếp tục? (Y/N)
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Chờ người dùng trả lời rõ ràng "Y" hoặc "N" rồi mới tiếp tục.
|
|
98
|
-
- "Y" → tiếp tục sang các bước riêng của lệnh bên dưới.
|
|
99
|
-
- "N" → dừng lại và hỏi người dùng muốn thay đổi gì.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
*Lưu ý: Với lệnh này, target ở Bước 1 là một tên domain hoặc UC-ID cụ thể từ `$ARGUMENTS`. Không có một file đơn để phân giải — lệnh quét nhiều thư mục.*
|
|
103
|
-
|
|
104
|
-
## Context
|
|
105
|
-
# Context Loader — Nạp toàn bộ context dự án
|
|
106
|
-
|
|
107
|
-
Thực hiện các bước theo đúng thứ tự. Lưu mọi thứ vào bộ nhớ trong suốt phiên làm việc của lệnh.
|
|
108
|
-
|
|
109
|
-
**Hướng dẫn ưu tiên (chống lost-in-middle):**
|
|
110
|
-
- Bước 1–2 là PROJECT-CONFIG — nạp trước, phân giải mọi path và metadata.
|
|
111
|
-
- Bước 3 là CRITICAL — kiến trúc + coding standards, là các sự thật ưu tiên cao nhất khi sinh nội dung.
|
|
112
|
-
- Bước 4 là SAFETY — quy tắc bảo vệ dữ liệu, thực thi ngầm suốt cả phiên.
|
|
113
|
-
- Bước 5–6 là DOMAIN KNOWLEDGE — thuật ngữ và định nghĩa entity.
|
|
114
|
-
- Bước 7 là WORKING MEMORY RECAP — chốt các sự thật quan trọng lên đầu bộ nhớ làm việc.
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## Bước 1 — [PROJECT-CONFIG] Nạp project-context.yaml
|
|
119
|
-
|
|
120
|
-
Đọc `.agent/project-context.yaml`. Trích xuất và lưu:
|
|
121
|
-
|
|
122
|
-
**Tech Stack:**
|
|
123
|
-
- `tech_stack.language` → ngôn ngữ đang dùng (vd: Java 17, TypeScript, C#, Go)
|
|
124
|
-
- `tech_stack.framework` → framework đang dùng (vd: Spring Boot 3.2, Angular 17, .NET 8)
|
|
125
|
-
- `tech_stack.build_tool` → build tool (vd: Maven, npm, dotnet, go)
|
|
126
|
-
- `tech_stack.test_framework` → test framework (vd: JUnit 5 + Mockito, Jest, xUnit)
|
|
127
|
-
- `tech_stack.database` → database (vd: PostgreSQL, MySQL, MongoDB)
|
|
128
|
-
- `tech_stack.module` → module profile đang dùng (vd: java-spring, angular, dotnet, golang, context-engineering)
|
|
129
|
-
|
|
130
|
-
**Conventions:**
|
|
131
|
-
- `conventions.build_command` → cách compile/build
|
|
132
|
-
- `conventions.test_command` → cách chạy test
|
|
133
|
-
- `conventions.service_run` → cách khởi động service
|
|
134
|
-
- `conventions.ticket_prefix` → tiền tố ticket ID (vd: PROJ, FEAT, UC)
|
|
135
|
-
|
|
136
|
-
**Domains:**
|
|
137
|
-
- `domains` → danh sách các business domain đang hoạt động
|
|
138
|
-
|
|
139
|
-
**Paths (nếu có):**
|
|
140
|
-
- `paths.specs_dir` → gốc của spec artifact — PRD, BDD, tech-docs, design-spec. Cấu trúc: `{specs_dir}/{domain}/{prd-slug}/{ {TICKET-ID}-{prd-slug}.md | bdd/ | tech-docs/ | design-spec/}` (file PRD đặt tên `{TICKET-ID}-{prd-slug}.md`, là file `.md` duy nhất ở gốc feature folder)
|
|
141
|
-
- `paths.refinement_dir` → thư mục output cho findings/review
|
|
142
|
-
- `paths.qc_dir` → gốc artifact QC automation (hiện ở top-level, mỗi UC một thư mục con: `{qc_dir}/{UC-ID}/`)
|
|
143
|
-
- `paths.qc_skills_dir` → nơi các lệnh qc-* nạp QC skill (mặc định bundled `.agent/skills/qc`; override sang repo/submodule riêng của team QC để bản nâng cấp framework không ghi đè)
|
|
144
|
-
- `paths.product_definitions_dir` → gốc product definition
|
|
145
|
-
- `paths.domain_knowledge_dir` → gốc domain knowledge
|
|
146
|
-
- `paths.business_dictionary` → path tới business-dictionary.md
|
|
147
|
-
- `paths.core_entities` → path tới core-entities.md
|
|
148
|
-
- `paths.tech_docs_dir` → gốc tài liệu kỹ thuật (gộp với specs_dir trong bố cục feature-package — tech-docs nằm dưới `{specs_dir}/{domain}/{prd-slug}/tech-docs/`)
|
|
149
|
-
- `paths.src_dir` → gốc mã nguồn (nơi generate-code đặt & quét code; nguồn chính cho FE + phạm vi reuse-scan của DS5)
|
|
150
|
-
- `paths.trace_dir` → thư mục trạng thái trace; cấu trúc: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` (mỗi UC × platform một sổ)
|
|
151
|
-
|
|
152
|
-
Nếu không có section `paths`, dùng các giá trị mặc định:
|
|
153
|
-
- `specs_dir` = `specs`
|
|
154
|
-
- `refinement_dir` = `.agent/review`
|
|
155
|
-
- `qc_dir` = `docs`
|
|
156
|
-
- `qc_skills_dir` = `.agent/skills/qc`
|
|
157
|
-
- `product_definitions_dir` = `specs/product-definition`
|
|
158
|
-
- `domain_knowledge_dir` = `specs/domain-knowledge`
|
|
159
|
-
- `business_dictionary` = `specs/domain-knowledge/business-dictionary.md`
|
|
160
|
-
- `core_entities` = `specs/domain-knowledge/core-entities.md`
|
|
161
|
-
- `tech_docs_dir` = `specs`
|
|
162
|
-
- `src_dir` = `src`
|
|
163
|
-
- `trace_dir` = `.trace`
|
|
164
|
-
|
|
165
|
-
Lưu ý: Trong bố cục feature-package, `specs_dir` là gốc thống nhất. Mọi loại spec artifact (PRD, BDD, tech-docs, design-spec) đều nằm dưới `{specs_dir}/{domain}/{prd-slug}/`. `prd-slug` là tên folder feature-package, không phải một biến config riêng.
|
|
166
|
-
|
|
167
|
-
**Cách trích xuất `prd_slug` (đúng cho MỌI target file, bất kể độ sâu lồng nhau):** với một path target dạng `{specs_dir}/{domain}/{prd-slug}/...`, lấy **segment path đầu tiên sau `{specs_dir}/{domain}/`** — tức vị trí `{prd-slug}`. KHÔNG dùng folder cha trực tiếp của file, vì artifact BDD/tech-docs/design-spec lồng sâu hơn một hoặc hai cấp bên trong package. Ví dụ:
|
|
168
|
-
- `specs/payment/create-invoice/PAY01-create-invoice.md` → `prd_slug = create-invoice`
|
|
169
|
-
- `specs/payment/create-invoice/bdd/system/PAY-UC1.feature` → `prd_slug = create-invoice` *(KHÔNG phải `system`)*
|
|
170
|
-
- `specs/payment/create-invoice/bdd/web/PAY-UC1.feature` → `prd_slug = create-invoice` *(KHÔNG phải `web`)*
|
|
171
|
-
- `specs/payment/create-invoice/tech-docs/PAY01-tech-design.md` → `prd_slug = create-invoice` *(KHÔNG phải `tech-docs`)*
|
|
172
|
-
- `specs/payment/create-invoice/design-spec/PAY-design-spec-web.md` → `prd_slug = create-invoice`
|
|
173
|
-
|
|
174
|
-
Mọi artifact cùng cấp của một feature (PRD, BDD của từng platform, tech-docs BE + FE, design-spec, và trace TSV) đều phân giải về **cùng một `prd_slug`** — nên một BDD **system** hay tech-doc **system/BE** được tổng hợp sẽ nằm chung package `{specs_dir}/{domain}/{prd-slug}/` với các artifact web/app mà nó được suy ra từ đó.
|
|
175
|
-
|
|
176
|
-
Nếu `tech_stack.module` được đặt, đồng thời nạp `.agent/modules/{module}/stack-profile.yaml` nếu file tồn tại.
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Bước 1.5 — [SERVICE ROUTING] Phân giải path service (chế độ umbrella)
|
|
181
|
-
|
|
182
|
-
*Bỏ qua hoàn toàn bước này nếu `setup.mode` không phải `"umbrella"` và không có section `services` trong project-context.yaml.*
|
|
82
|
+
*Bỏ qua nếu `_agent_mode: true`.*
|
|
183
83
|
|
|
184
|
-
|
|
84
|
+
### 3a — Lệnh này có phải chặn không?
|
|
185
85
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
86
|
+
| Mức | Lệnh nào | `--yes` bỏ qua được? |
|
|
87
|
+
|---|---|:---:|
|
|
88
|
+
| **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
|
|
89
|
+
| **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
|
|
90
|
+
| **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
|
|
191
91
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
- Nếu vẫn không xác định được → `active_platform = null`.
|
|
92
|
+
`--yes` trong `$ARGUMENTS` → bỏ qua CHECKPOINT mức *chặn thường*. (Bước 1 đã tách mọi token
|
|
93
|
+
`--` khỏi phần resolve target, nên cờ này không ảnh hưởng việc tìm file.) Mở đường chạy
|
|
94
|
+
headless: `claude -p "/generate-code UC1 --yes"`.
|
|
196
95
|
|
|
197
|
-
**
|
|
96
|
+
> **KHÔNG tự suy mức từ bảng này.** Mỗi lệnh **tự khai** mức của nó ở một dòng `*Checkpoint: …*`
|
|
97
|
+
> ngay dưới `## Gate` của chính nó — đọc dòng đó, đừng suy diễn. Bảng trên chỉ giải thích ba mức
|
|
98
|
+
> **nghĩa là gì**.
|
|
99
|
+
> Nguồn máy đọc: `bin/trace-schema.json` → `gate.checkpoint_levels`; `self-check` **R11** fail
|
|
100
|
+
> build nếu nhãn trong file lệnh lệch với schema, hoặc nếu một lệnh `hard`/`none` thiếu nhãn.
|
|
101
|
+
> *(Lệnh không có dòng nào = mức **chặn thường**, mặc định.)*
|
|
198
102
|
|
|
199
|
-
|
|
103
|
+
> **Mức *không chặn* là thực thi đúng miễn trừ mà `rules/workflow.md` đã cấp từ trước** —
|
|
104
|
+
> trước G41 file đó viết *"read-only commands may skip CHECKPOINT"* còn gate thì luôn đòi.
|
|
105
|
+
> Hai file cùng được nạp vào mọi lệnh mà nói ngược nhau; agent theo cái nào là tuỳ lúc.
|
|
200
106
|
|
|
201
|
-
|
|
107
|
+
### 3b — In gì
|
|
202
108
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
| **Tra tiếp** | có `by_prd_slug` | Ô này còn nhiều submodule → tra thêm một nấc bằng `prd_slug` (2c) |
|
|
207
|
-
|
|
208
|
-
**Kiểm tra hợp lệ TRƯỚC khi dùng một entry** (làm ngay, đừng đợi tới 2a/2b/2c — sai ở đây mà đi tiếp là route nhầm repo mà không báo gì):
|
|
209
|
-
|
|
210
|
-
| Entry trông thế nào | Xử lý |
|
|
211
|
-
|---|---|
|
|
212
|
-
| có `path`, không có `by_prd_slug` | hợp lệ → dùng |
|
|
213
|
-
| có `by_prd_slug`, không có `path` | hợp lệ → tra tiếp (2c) |
|
|
214
|
-
| **có CẢ HAI** | ❌ lỗi cấu hình → `active_service = unresolved`. **KHÔNG** ưu tiên `path` rồi bỏ qua `by_prd_slug` — như vậy mọi feature sẽ âm thầm route về cùng một repo. Báo đúng key sai để người dùng sửa. |
|
|
215
|
-
| **không có cái nào** (và cũng không phải map platform) | ❌ lỗi cấu hình → `unresolved`, nêu rõ entry thiếu `path`/`by_prd_slug` |
|
|
216
|
-
| `by_prd_slug` chứa entry lại có `by_prd_slug` | ❌ lỗi cấu hình → `unresolved`. Chỉ tra đúng **một** nấc slug, không đệ quy |
|
|
109
|
+
**KHÔNG lặp lại những gì `[CTX LOADED]` vừa in.** Recap của context-loader (Bước 7) đã hiện
|
|
110
|
+
Stack · Platform · Layers · CLAUDE.md · Dict · Entities · Lessons · Service · Status ngay phía
|
|
111
|
+
trên. CHECKPOINT chỉ thêm **một** thông tin mới là `Target`.
|
|
217
112
|
|
|
218
|
-
|
|
113
|
+
**Mọi thứ sạch** — recap báo `Status: FULL`, không cờ nào bật → in đúng hai dòng:
|
|
219
114
|
|
|
220
|
-
| Thấy gì trong `services.{domain}` | Đi nhánh |
|
|
221
|
-
|---|---|
|
|
222
|
-
| có `path` | **2a** — chốt luôn |
|
|
223
|
-
| có `by_prd_slug` | **2c** — tra bằng `prd_slug` |
|
|
224
|
-
| không có cả hai (chỉ có các sub-key `system`/`web`/`app`…) | **2b** — tra bằng `platform`, rồi lặp lại đúng bảng này cho entry con |
|
|
225
|
-
|
|
226
|
-
**2a. Dạng phẳng** — `services.{domain}` có **trực tiếp** `path`/`module` (một domain ↔ một service, mọi platform về cùng submodule). Route như cũ:
|
|
227
|
-
- Lưu `active_service` = `services.{domain}.path`
|
|
228
|
-
- Lưu `active_service_module` = `services.{domain}.module`
|
|
229
|
-
- Nếu service có `module` riêng → dùng nó làm `active_module` (override `tech_stack.module`)
|
|
230
|
-
|
|
231
|
-
**2b. Dạng map-theo-platform** — `services.{domain}` **KHÔNG** có `path` trực tiếp mà chứa các sub-key platform (`system` / `web` / `app`), mỗi cái là một **service entry** (một business-domain trải trên nhiều platform/submodule). Route theo `active_platform` (bước 1b):
|
|
232
|
-
- Nếu `active_platform` khớp một sub-key → `entry = services.{domain}.{active_platform}`. Nếu `entry` có `path` → lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`). Nếu `entry` có `by_prd_slug` → **đi tiếp sang 2c** với entry đó.
|
|
233
|
-
- Nếu `active_platform = null` (chưa xác định platform, vd đang thao tác cấp PRD) → **KHÔNG** chốt một service; đặt `active_service = multi`, `service_candidates_kind = platform`, và lưu `service_candidates` = map platform→`{path, module}`. **Làm phẳng luôn ở đây:** platform nào có entry `by_prd_slug` thì giải bằng `prd_slug` hiện tại (target cấp PRD vẫn nằm trong một feature-package nên `prd_slug` đã biết từ bước 1) → `service_candidates.{platform}` vẫn là `{path, module}` phẳng. Nếu `prd_slug` không khớp key nào, ghi platform đó là `unresolved` kèm lý do thay vì bỏ im. Nhờ vậy **mọi lệnh downstream chỉ cần biết một kiểu `service_candidates`**. Lệnh cần một service cụ thể (`/generate-code`, `/dev-*`, `/fix-bug`) luôn chạy trên target `.feature` có platform nên sẽ resolve được ở lần chạy đó; lệnh cấp PRD (`/generate-prd`, `/refine-prd`) không cần service cụ thể.
|
|
234
|
-
- Nếu `active_platform` xác định nhưng không có sub-key tương ứng → `active_service = unresolved` (xem Fallback) với lý do "domain `{domain}` chưa cấu hình platform `{active_platform}`".
|
|
235
|
-
|
|
236
|
-
**2c. Dạng map-theo-prd_slug** — một service entry chứa `by_prd_slug` thay cho `path`: **một ô của bảng định tuyến ứng với NHIỀU submodule**, mỗi feature-package một submodule. Dùng khi một platform (hoặc cả một domain) bị chia thành nhiều repo theo feature — ví dụ mỗi mini-game webview là một repo riêng.
|
|
237
|
-
|
|
238
|
-
Đến đây `prd_slug` đã được trích ở bước 1 (không cần detect thêm gì). Route:
|
|
239
|
-
|
|
240
|
-
- Nếu `prd_slug` khớp một key dưới `by_prd_slug` → `entry = {…}.by_prd_slug.{prd_slug}`; lưu `active_service = entry.path`, `active_service_module = entry.module` (→ `active_module`, override `tech_stack.module`).
|
|
241
|
-
**"Khớp" ở đây là khớp CHÍNH XÁC toàn chuỗi, phân biệt hoa/thường.** KHÔNG prefix, KHÔNG bỏ hậu tố, KHÔNG so gần đúng: `dap-chuot-v2` **không** khớp key `dap-chuot`; `Ban-Cung` **không** khớp `ban-cung`. Feature mới tách ra từ một feature cũ là một repo khác cho tới khi có người khai nó vào bảng.
|
|
242
|
-
- Nếu `prd_slug = null` (chưa xác định feature-package — chỉ xảy ra khi không có target file, vd `$ARGUMENTS` rỗng) → **KHÔNG** chốt một service; đặt `active_service = multi`, `service_candidates_kind = prd_slug`, và lưu `service_candidates` = toàn map `by_prd_slug` (slug → `{path, module}`).
|
|
243
|
-
⚠️ Đây là kiểu `service_candidates` **khác** với 2b — lệnh nào duyệt `service_candidates` theo platform (vd `/generate-bdd` sinh `bdd/{platform}/`) phải kiểm `service_candidates_kind = platform` trước; gặp `prd_slug` thì DỪNG và yêu cầu người dùng chỉ rõ target, đừng coi slug là platform.
|
|
244
|
-
- Nếu `prd_slug` xác định nhưng **không** có key tương ứng → `active_service = unresolved` với lý do rõ: "domain `{domain}`{, platform `{active_platform}`} chưa cấu hình prd_slug `{prd_slug}`". **KHÔNG** tự đoán submodule gần đúng theo tên.
|
|
245
|
-
|
|
246
|
-
Vị trí đặt `by_prd_slug` — hợp lệ ở **cả hai cấp**:
|
|
247
|
-
- **Dưới một platform** (lồng trong 2b): `services.{domain}.{platform}.by_prd_slug` — platform đó có nhiều repo, các platform khác vẫn `{path, module}` như thường.
|
|
248
|
-
- **Ngay dưới domain** (thay cho `path` của 2a): `services.{domain}.by_prd_slug` — domain không chia platform nhưng vẫn nhiều repo theo feature.
|
|
249
|
-
|
|
250
|
-
*(`by_prd_slug` lồng trong `by_prd_slug` là vô nghĩa — nếu gặp, coi là lỗi cấu hình: `active_service = unresolved`, nêu rõ để người dùng sửa file. Một entry vừa có `path` vừa có `by_prd_slug` cũng là lỗi cấu hình — báo lỗi, không âm thầm ưu tiên cái nào.)*
|
|
251
|
-
|
|
252
|
-
Ví dụ (một domain trải nhiều platform, riêng `webview` chia theo feature):
|
|
253
|
-
```yaml
|
|
254
|
-
services:
|
|
255
|
-
learning:
|
|
256
|
-
system: { path: "backend", module: "java-spring" }
|
|
257
|
-
web: { path: "web-app", module: "nextjs" }
|
|
258
|
-
webview:
|
|
259
|
-
by_prd_slug:
|
|
260
|
-
dap-chuot: { path: "games/whac-a-mole", module: "phaser-game" }
|
|
261
|
-
ban-cung: { path: "games/archery", module: "phaser-game" }
|
|
262
115
|
```
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
*(Cả 2a/2b/2c: override `paths.specs_dir`/`paths.tech_docs_dir` per-service CHỈ khi `setup.spec_source` KHÔNG được đặt. Khi `spec_source` ĐƯỢC đặt, MỌI BDD/tech-doc là artifact liên team → để bước 4 route sang spec repo; KHÔNG pin per-service ở đây.)*
|
|
267
|
-
|
|
268
|
-
**3. Fallback**:
|
|
269
|
-
- Không phát hiện được domain, hoặc domain không khớp key nào trong `services` → giữ path mặc định từ Bước 1, đặt `active_service = unresolved`.
|
|
270
|
-
- Domain khớp một map-theo-platform (2b) nhưng `active_platform` xác định mà thiếu sub-key tương ứng → `active_service = unresolved`, ghi lý do rõ để lệnh DỪNG báo lỗi cấu hình (không tự đoán platform).
|
|
271
|
-
- Entry là map-theo-prd_slug (2c) nhưng `prd_slug` xác định mà thiếu key tương ứng → `active_service = unresolved`, ghi lý do rõ (không tự đoán submodule).
|
|
272
|
-
- Entry sai cấu trúc (vừa có `path` vừa có `by_prd_slug`, hoặc `by_prd_slug` lồng nhau) → `active_service = unresolved`, nêu đúng key sai để người dùng sửa `project-context.yaml`.
|
|
273
|
-
|
|
274
|
-
**4. Tự động override theo spec source** — nếu `setup.spec_source` được đặt VÀ path tương ứng chưa được set tường minh trong `paths:`:
|
|
275
|
-
- Override `paths.specs_dir` → `{spec_source}/specs` — **luôn khi `spec_source` được đặt.** Mọi spec artifact (PRD, BDD, tech-docs, design-spec) nằm dưới gốc spec thống nhất trong spec repo dùng chung theo bố cục feature-package: `{spec_source}/specs/{domain}/{prd-slug}/`. Mọi umbrella (FE/App/BE) đều đọc từ đây. *(`specs/` theo service chỉ khi không có `spec_source`.)*
|
|
276
|
-
- Override `paths.tech_docs_dir` → `{spec_source}/specs` — **luôn khi `spec_source` được đặt** (bước 2 không còn pin tech-docs theo service trong trường hợp này). Tech-docs nằm tại `{spec_source}/specs/{domain}/{prd-slug}/tech-docs/`. Tech-design CHÍNH LÀ API contract liên team: BE viết ở đây, FE/App đọc nó từ cùng spec submodule tại `/generate-code --phase=integration`. *(tech-docs theo service chỉ xảy ra khi không có `spec_source` — repo BE thuần đa-service không có spec module dùng chung.)*
|
|
277
|
-
- Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
|
|
278
|
-
- Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
|
|
279
|
-
- Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
|
|
280
|
-
- Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
|
|
281
|
-
- Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
|
|
282
|
-
- Override `paths.prd_change_requests_dir` → `{spec_source}/feedback/prd-change-requests`
|
|
283
|
-
- Override `paths.trace_dir` → `{spec_source}/.trace` — **luôn khi `spec_source` được đặt.** Trace TSV được gộp vào spec repo (một nơi authoritative duy nhất, không tách theo service) để PM/PO có một chỗ duy nhất quản lý trạng thái. Cấu trúc bên trong: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv`. Các lệnh phía code (`/generate-code`, `/dev-run-test`, `/qc-run-test`) chạy từ `service_root` nhưng **ghi trace row của chúng vào `{spec_source}/.trace/{domain}/{prd-slug}/`** — giống như chúng đã push `feedback/` vào đó. *(`.trace` theo service chỉ khi không có `spec_source`.)*
|
|
284
|
-
- Override `paths.refinement_dir` → `{spec_source}/.agent/review` — **luôn khi `spec_source` được đặt.** Findings review (`/refine-prd`, `/review-context`, `/review-tech-docs`) là artifact liên-team *về* tài liệu trong spec repo (PRD/BDD/tech-design) — thuộc cùng khu vực ghi với `.trace/` và `feedback/`. Các lệnh review chạy từ working dir của service (BE repo) nhưng **ghi findings vào `{spec_source}/.agent/review/`**, KHÔNG phải `.agent/review` của service repo. Bên trong flat, phân biệt bằng tên file đã prefix `{prd-slug}`/`{UC-ID}`/`{TICKET-ID}`. *(`.agent/review` theo service chỉ khi không có `spec_source`.)*
|
|
285
|
-
|
|
286
|
-
> **Vì sao đặt dưới `spec_source`:** PRD, BDD, tech-docs, design-spec, domain knowledge, feedback của tester, **trạng thái coverage `.trace/`**, **và findings review `.agent/review/`** đều là **artifact liên team** — chúng nằm trong **spec repo dùng chung** theo bố cục feature-package để mọi umbrella (FE/App/BE) và PM đọc từ một nguồn qua `/sync`. Trong bố cục feature-package, một folder `specs/{domain}/{prd-slug}/` gom tất cả loại artifact của một PRD, giúp spec repo tự đủ và dễ điều hướng theo feature. Service submodule chỉ chứa **code** (+ tooling build/test). `.trace/`, `.agent/review/` và `feedback/` là khu vực **ghi** của dev/QC/reviewer trong spec repo. Ở chế độ single-service (không có `spec_source`), mọi thứ mặc định dưới gốc repo — vẫn là một repo.
|
|
287
|
-
|
|
288
|
-
---
|
|
289
|
-
|
|
290
|
-
## Bước 1.6 — [SERVICE CONVENTIONS] Nạp convention riêng của service (chế độ umbrella)
|
|
291
|
-
|
|
292
|
-
*Bỏ qua hoàn toàn bước này nếu `active_service` là `"unresolved"` hoặc `"multi"` (chưa chốt một service — dạng map-theo-platform ở cấp PRD) hoặc context ở chế độ single-service.*
|
|
293
|
-
|
|
294
|
-
Khi `active_service` đã được phân giải thành một path thật ở Bước 1.5 (vd: `user-service/`):
|
|
295
|
-
|
|
296
|
-
**1. Định vị config của service** — thử theo thứ tự ưu tiên:
|
|
297
|
-
- `{active_service}/.agent/project-context.yaml`
|
|
298
|
-
- `{active_service}/project-context.yaml`
|
|
299
|
-
|
|
300
|
-
**2. Nếu tìm thấy, override bằng giá trị riêng của service:**
|
|
301
|
-
|
|
302
|
-
| Biến | Nguồn |
|
|
303
|
-
|----------|--------|
|
|
304
|
-
| `conventions.test_command` | `conventions.test_command` của service |
|
|
305
|
-
| `conventions.build_command` | `conventions.build_command` của service |
|
|
306
|
-
| `paths.trace_dir` | **Nếu `spec_source` được đặt → giữ route spec-repo của bước 4 (`{spec_source}/.trace`); bỏ qua mọi `trace_dir` cấp service.** Chỉ khi không có `spec_source`: `{active_service}/{service paths.trace_dir}` (mặc định `{active_service}/.trace`). |
|
|
307
|
-
| `paths.specs_dir` | **Nếu `spec_source` được đặt → giữ route spec-repo của bước 4 (`{spec_source}/specs`); bỏ qua mọi `specs_dir` cấp service** (mọi spec artifact đều liên team, không bao giờ theo service ở chế độ này). Chỉ khi không có `spec_source`: `{active_service}/{service paths.specs_dir}` nếu được set, else dùng override ở Bước 1.5. |
|
|
308
|
-
| `paths.refinement_dir` | **Nếu `spec_source` được đặt → giữ route spec-repo của bước 4 (`{spec_source}/.agent/review`); bỏ qua mọi `refinement_dir` cấp service** (findings review là artifact liên team). Chỉ khi không có `spec_source`: `{active_service}/.agent/review`. |
|
|
309
|
-
|
|
310
|
-
**3. Lưu** `service_root = {active_service}` làm mốc thư mục làm việc cho mọi lệnh phía sau:
|
|
311
|
-
- Các lệnh shell (`/dev-run-test`, `/dev-gen-test`) chạy **bên trong** `service_root`
|
|
312
|
-
- **File source/test** được ghi tương đối với `service_root`; **trace TSV** được ghi vào `{paths.trace_dir}` (là spec repo khi `spec_source` được đặt — một thao tác ghi liên-repo, commit/push vào spec submodule giống như `feedback/`).
|
|
313
|
-
|
|
314
|
-
**4. Nếu không tìm thấy config của service** — giữ mặc định umbrella, vẫn set `service_root = {active_service}` (luôn cần mốc path kể cả khi không có config override).
|
|
315
|
-
|
|
316
|
-
---
|
|
317
|
-
|
|
318
|
-
## Bước 2 — [PROJECT-CONFIG] Nạp module stack profile (có điều kiện)
|
|
319
|
-
|
|
320
|
-
Nếu `tech_stack.module` được đặt, đọc `.agent/modules/{module}/stack-profile.yaml`.
|
|
321
|
-
Merge các convention riêng của framework (layer pattern, test pattern, quy tắc đặt tên) vào context đã nạp.
|
|
322
|
-
Nếu file không tồn tại → bỏ qua âm thầm.
|
|
323
|
-
|
|
324
|
-
---
|
|
325
|
-
|
|
326
|
-
## Bước 3 — [CRITICAL] Nạp CLAUDE.md (phân tầng: root + service overlay)
|
|
327
|
-
|
|
328
|
-
*Đây là context ưu tiên cao nhất — nó định nghĩa CÁCH viết code và tài liệu cho dự án này.*
|
|
329
|
-
|
|
330
|
-
CLAUDE.md được nạp theo **hai tầng** để các quy tắc toàn-umbrella và kiến trúc/coding standards
|
|
331
|
-
riêng của service kết hợp đúng cách. Agent luôn đứng ở gốc umbrella, nhưng code triển khai nằm
|
|
332
|
-
trong một service submodule với stack, kiến trúc, và convention RIÊNG của nó — nên CLAUDE.md của
|
|
333
|
-
service phải thắng khi sinh code.
|
|
334
|
-
|
|
335
|
-
**Tầng 1 — [BASE] Root CLAUDE.md (toàn umbrella).**
|
|
336
|
-
Đọc `CLAUDE.md` ở gốc repo. Coi nội dung của nó là **nền tảng dùng chung** cho cả umbrella —
|
|
337
|
-
git convention, tư thế bảo vệ dữ liệu, quy tắc xuyên suốt, và (ở chế độ single-service) là
|
|
338
|
-
kiến trúc + coding standards duy nhất của dự án.
|
|
339
|
-
|
|
340
|
-
**Tầng 2 — [OVERLAY] Service CLAUDE.md (chỉ chế độ umbrella).**
|
|
341
|
-
*Chỉ chạy nếu `service_root` đã được set ở Bước 1.6 (tức đã route tới một service thật).*
|
|
342
|
-
Đọc `{service_root}/CLAUDE.md`. File này định nghĩa kiến trúc + coding standards của **stack
|
|
343
|
-
thực sự đang được triển khai** (vd: `user-service` = java-spring, `web` = nextjs).
|
|
344
|
-
Overlay nó lên trên Tầng 1: **khi có xung đột, giá trị của service THẮNG** cho kiến trúc,
|
|
345
|
-
coding standards, và error handling. Các giá trị Tầng 1 mà service không định nghĩa lại
|
|
346
|
-
(vd: git convention, banned pattern dùng chung toàn tổ chức) vẫn có hiệu lực.
|
|
347
|
-
|
|
348
|
-
Từ kết quả **đã merge**, trích xuất và lưu:
|
|
116
|
+
CHECKPOINT — Target: {resolved file path}
|
|
117
|
+
Tiếp tục? (Y/N)
|
|
118
|
+
```
|
|
349
119
|
|
|
350
|
-
|
|
351
|
-
- **§2 Architecture** → thứ tự layer (vd: Controller → Facade → Service → Repository), quy tắc kiến trúc — *service overlay thắng*
|
|
352
|
-
- **§2 Package Layout** → **base package** (vd `vn.edupia.{service}`) + **chiến lược đặt package** (by-layer / by-feature) + nơi code một domain sống. Đây là **quy ước đặt code trên đĩa**, PHẢI enforce khi sinh code. Nếu §2 chỉ nêu base package + thứ tự layer mà **không** nói tới sub-package theo feature → hiểu là **by-layer**: các layer đặt **TRỰC TIẾP** dưới base package (vd `vn.edupia.{service}.service`, `.repository`); feature/UC/prd-slug **KHÔNG** thành sub-package, chỉ phân biệt ở **tên class**. Lưu `code_base_package` + `package_strategy` — *service overlay thắng*.
|
|
353
|
-
- **§3 Coding Standards** → quy tắc đặt tên (class, method), kiểu response wrapper, pattern bị cấm — *service overlay thắng*
|
|
354
|
-
- **§5 Error Handling** → kiểu exception, mapping HTTP status code, tên class not-found exception — *service overlay thắng*
|
|
355
|
-
- **§7 Git Conventions** → pattern đặt tên branch, format commit message — *lấy theo root trừ khi service định nghĩa lại*
|
|
120
|
+
**Có bất thường** → thêm một dòng cho **mỗi** trạng thái, nặng nhất lên đầu:
|
|
356
121
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
122
|
+
```
|
|
123
|
+
CHECKPOINT
|
|
124
|
+
🔴 Service : unresolved — {lý do context-loader đã ghi}
|
|
125
|
+
⚠️ CLAUDE.md: service overlay THIẾU — dùng root (code sinh ra có thể sai stack)
|
|
126
|
+
⚠️ Target : resolve bằng wildcard — {n} file khớp, chọn {file}
|
|
127
|
+
⚠️ Module : not configured — code sinh ra sẽ dùng default
|
|
128
|
+
Status : PARTIAL — thiếu: {danh sách}
|
|
129
|
+
Target : {resolved file path}
|
|
130
|
+
Tiếp tục? (Y/N)
|
|
131
|
+
```
|
|
362
132
|
|
|
363
|
-
|
|
133
|
+
### 3c — Cờ nào bật, cờ nào KHÔNG
|
|
364
134
|
|
|
365
|
-
|
|
135
|
+
Mỗi dòng ⚠️/🔴 phải ứng với một trạng thái **context-loader đã tính rồi** — không phát minh
|
|
136
|
+
điều kiện mới, chỉ mang thứ đang bị giấu lên chỗ người dùng phải quyết định:
|
|
366
137
|
|
|
367
|
-
|
|
138
|
+
| Bật cờ khi | Nguồn | Mức |
|
|
139
|
+
|---|---|:---:|
|
|
140
|
+
| `active_service = unresolved` | context-loader Bước 2b/2c/Fallback | 🔴 |
|
|
141
|
+
| `Status = MINIMAL` | recap Bước 7 | 🔴 |
|
|
142
|
+
| `Status = PARTIAL` | recap Bước 7 | ⚠️ |
|
|
143
|
+
| CLAUDE.md thiếu, hoặc service overlay thiếu | context-loader Bước 3 | ⚠️ |
|
|
144
|
+
| Target resolve qua wildcard, hoặc nhiều file khớp mà lệnh tự chọn | Bước 1 ở trên | ⚠️ |
|
|
145
|
+
| `module` không cấu hình | recap Bước 7 | ⚠️ |
|
|
368
146
|
|
|
369
|
-
|
|
147
|
+
**KHÔNG bật cờ cho:** `Lessons: chưa có` · `Dict: missing` · `Entities: missing`. Đó là
|
|
148
|
+
*"dự án chưa điền"*, không phải *"có gì đó sai"* — chúng ở lại trong recap.
|
|
370
149
|
|
|
371
|
-
|
|
150
|
+
> **Nguyên tắc một câu:** cờ dành cho thứ **framework không chắc chắn hoặc đã phải đoán**,
|
|
151
|
+
> không dành cho thứ **người dùng chưa làm**. Đẩy hết mọi thứ lên thì CHECKPOINT lại đầy như
|
|
152
|
+
> cũ, và ta quay về đúng chỗ xuất phát: một cổng luôn giống nhau thì bị lướt qua.
|
|
372
153
|
|
|
373
|
-
|
|
154
|
+
### 3d — Chờ trả lời
|
|
374
155
|
|
|
375
|
-
|
|
156
|
+
- "Y" → tiếp tục sang các bước riêng của lệnh.
|
|
157
|
+
- "N" → dừng, hỏi người dùng muốn thay đổi gì.
|
|
158
|
+
- Có `--yes` và mức *chặn thường* → coi như "Y", **nhưng vẫn IN khối CHECKPOINT** nếu có cờ
|
|
159
|
+
🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
|
|
376
160
|
|
|
377
|
-
Kiểm tra file business dictionary có tồn tại không (dùng `paths.business_dictionary` đã phân giải ở Bước 1).
|
|
378
161
|
|
|
379
|
-
|
|
380
|
-
- **Canonical Terms** → danh sách đầy đủ các thuật ngữ chuẩn và định nghĩa
|
|
381
|
-
- **Banned Terms** → danh sách đầy đủ các thuật ngữ bị cấm và bản thay thế chuẩn
|
|
382
|
-
- **Status / Enum Registry** → các giá trị enum được phép theo từng entity
|
|
162
|
+
*Lưu ý: Lệnh này **không có target file đơn** — nó quét nhiều thư mục, nên gate Bước 1 không phân giải file. Phạm vi audit do **Step 0-A** phân giải từ `$ARGUMENTS` (`--domain` / `--prd` / `--uc`; không có cờ nào = toàn bộ).*
|
|
383
163
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
164
|
+
## Context
|
|
165
|
+
**BẮT BUỘC — đọc `.agent/steps/context-loader.md` và thực thi TOÀN BỘ quy trình trong đó**,
|
|
166
|
+
rồi mới tiếp tục phần bên dưới.
|
|
387
167
|
|
|
388
|
-
|
|
168
|
+
Bỏ qua bước này thì `{paths.*}`, `{tech_stack.*}`, `{conventions.*}`, guardrail từ
|
|
169
|
+
`project-lessons`, và routing service (chế độ umbrella) đều **chưa được phân giải** — mọi
|
|
170
|
+
placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
389
171
|
|
|
390
172
|
---
|
|
391
173
|
|
|
392
|
-
##
|
|
174
|
+
## Process
|
|
393
175
|
|
|
394
|
-
|
|
395
|
-
Path mặc định: `specs/domain-knowledge/core-entities.md`.
|
|
176
|
+
### Step 0-A — Phân giải **phạm vi audit** *(chạy TRƯỚC Step 0)*
|
|
396
177
|
|
|
397
|
-
|
|
398
|
-
- **Entity catalog** → với mỗi entity: tên, mục đích, service sở hữu, các field chính (tên + kiểu), business invariant, và quan hệ
|
|
399
|
-
- **Field name registry** → tên field chuẩn dùng trong code và tài liệu được sinh ra
|
|
400
|
-
- **Relationship map** → cách các entity liên hệ với nhau (1:N, N:N, embedded, v.v.)
|
|
178
|
+
*Contract: `bin/trace-schema.json` → `gate.report_root_keys`. Đây là đầu PRODUCER của một sợi dây mà đầu CONSUMER (`gate-trace`) đã có sẵn từ trước.*
|
|
401
179
|
|
|
402
|
-
|
|
403
|
-
- Khi sinh code: dùng tên field, kiểu, và quan hệ định nghĩa ở đây — KHÔNG suy đoán từ code có sẵn
|
|
404
|
-
- Khi sinh PRD/BDD: tham chiếu tên entity từ catalog này để nhất quán
|
|
405
|
-
- Khi sinh tech-docs: dùng catalog này làm nguồn chân lý cho định nghĩa entity
|
|
180
|
+
Parse `$ARGUMENTS` (đã tách các cờ khác ở gate Bước 1):
|
|
406
181
|
|
|
407
|
-
|
|
182
|
+
| Cờ | `scope.kind` | `scope.value` | Hẹp lại những gì |
|
|
183
|
+
|---|---|---|---|
|
|
184
|
+
| *(không có)* | `all` | `"all"` | Không hẹp — audit toàn bộ |
|
|
185
|
+
| `--domain {domain}` | `domain` | tên domain | Chỉ sổ + spec dưới `{domain}/` |
|
|
186
|
+
| `--prd {TICKET-ID}` | `prd` | TICKET-ID | Chỉ **một** feature-package (phân giải `{domain}/{prd-slug}` từ TICKET-ID) |
|
|
187
|
+
| `--uc {UC-ID}` | `uc` | UC-ID | Chỉ **một** UC — **mọi platform của nó** (`{UC-ID}-*.tsv`) |
|
|
408
188
|
|
|
409
|
-
|
|
189
|
+
Nhiều cờ scope cùng lúc → **DỪNG**, báo lỗi: chúng loại trừ nhau, và tự ý ưu tiên một cái là hẹp phạm vi mà người dùng không biết.
|
|
410
190
|
|
|
411
|
-
|
|
191
|
+
`--prd`/`--uc` không phân giải được về một package/UC có thật → **DỪNG** và liệt kê ứng viên. **KHÔNG** âm thầm rơi về `all` (chạy toàn bộ khi người ta xin một phần là đốt 30 phút không ai muốn) và **KHÔNG** âm thầm audit rỗng (báo cáo "sạch" trên 0 row).
|
|
412
192
|
|
|
413
|
-
|
|
193
|
+
Lưu `scope` — mọi step sau dùng nó:
|
|
414
194
|
|
|
415
|
-
|
|
416
|
-
active_module = tech_stack.module (vd: "java-spring", "react", "flutter")
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
| `platform_type` | Modules |
|
|
195
|
+
| Step | Hẹp thế nào |
|
|
420
196
|
|---|---|
|
|
421
|
-
|
|
|
422
|
-
|
|
|
423
|
-
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
Hai biến này (`active_module`, `platform_type`) là nguồn chuẩn cho mọi logic rẽ nhánh trong các lệnh cần hành vi riêng theo platform (dev-gen-test, debug, fix-bug, dev-smoke-test).
|
|
428
|
-
|
|
429
|
-
---
|
|
430
|
-
|
|
431
|
-
## Bước 6.7 — [GUARDRAILS] Nạp Project Lessons (có điều kiện)
|
|
432
|
-
|
|
433
|
-
*Các lỗi tích luỹ mà AI không được lặp lại trong dự án này. Chúng được bổ sung dần qua `/learn`
|
|
434
|
-
hoặc được chấp nhận trong `/review-code`, `/fix-bug`, `/debug`.*
|
|
435
|
-
|
|
436
|
-
Phân giải path file lessons:
|
|
437
|
-
- Dùng `paths.lessons_file` nếu được set (có thể bị service override ở chế độ umbrella, Bước 1.6)
|
|
438
|
-
- Else mặc định `specs/domain-knowledge/lessons-learned.md`
|
|
439
|
-
- Ở chế độ umbrella/service (khi `service_root` được set), nếu `paths.lessons_file` chưa set, mặc định `{service_root}/.agent/project-lessons.md`
|
|
440
|
-
|
|
441
|
-
Nếu file tồn tại, đọc và lưu TẤT CẢ lesson làm **GUARDRAIL ĐANG HOẠT ĐỘNG** cho phiên:
|
|
442
|
-
- Coi **Rule** của mỗi lesson là ràng buộc cứng — cùng mức ưu tiên với coding standards trong CLAUDE.md (Bước 3).
|
|
443
|
-
- Trước khi sinh hoặc sửa bất kỳ artifact nào (PRD, BDD, tech-doc, code, test), đối chiếu output với mọi lesson có `category` khớp lệnh hiện tại VÀ `scope` khớp target (domain / file).
|
|
444
|
-
- Nếu output sinh ra vi phạm một lesson → sửa **trước khi** trình bày, và ghi rõ lesson nào (`L-NNN`) đã được áp dụng.
|
|
445
|
-
|
|
446
|
-
Nếu file không tồn tại → bỏ qua âm thầm (chưa có lesson nào được ghi nhận).
|
|
197
|
+
| Step 0 / Step 1 | `all_trace_dirs` giữ nguyên, nhưng chỉ đọc TSV **khớp scope**: `{trace_dir}/{domain}/**` · `{trace_dir}/{domain}/{prd-slug}/**` · `{trace_dir}/**/{UC-ID}-*.tsv` |
|
|
198
|
+
| Step 1.0 (lint) | truyền `--trace` như cũ — **lint luôn chạy toàn bộ**. Sổ hỏng ở domain khác vẫn là sổ hỏng, và lint rẻ (không LLM) |
|
|
199
|
+
| Step 2b · 3.9 · 4 · 5* · 7 | chỉ các PRD/UC trong scope |
|
|
200
|
+
| Step 6 · 6b | chỉ ghi lại TSV + mốc của phần trong scope |
|
|
201
|
+
| Step 8 | ghi `scope` **và** `domain` vào biên bản (xem dưới) |
|
|
447
202
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
## Bước 7 — [RECAP] Working Memory Recap (chống lost-in-middle)
|
|
451
|
-
|
|
452
|
-
Sau khi nạp toàn bộ context, tổng hợp và xuất một khối tóm tắt gọn.
|
|
453
|
-
Recap này đảm bảo các sự thật quan trọng nhất được nêu ở CUỐI quá trình nạp context
|
|
454
|
-
(hiệu ứng recency — tươi mới nhất trong bộ nhớ làm việc khi bắt đầu task).
|
|
455
|
-
|
|
456
|
-
Xuất đúng khối này:
|
|
203
|
+
**In phạm vi ngay đầu run**, trước khi làm gì:
|
|
457
204
|
```
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
Platform : {active_module} ({platform_type})
|
|
461
|
-
Layers : {thứ tự layer từ CLAUDE.md §2 đã merge, vd: Controller → Facade → Service → Repository}
|
|
462
|
-
Package : {code_base_package}.{layer} · {by-layer | by-feature} ← feature/UC → tên class, KHÔNG thành package (nếu by-layer)
|
|
463
|
-
CLAUDE.md : {root + {service_root} | chỉ {service_root} | chỉ root | ⚠️ service overlay THIẾU — dùng root | missing}
|
|
464
|
-
Ticket : {ticket_prefix}-
|
|
465
|
-
Dict : {loaded — N canonical terms, M banned terms | missing}
|
|
466
|
-
Entities : {loaded — EntityA, EntityB, EntityC | missing}
|
|
467
|
-
Lessons : {loaded — N guardrails | chưa có}
|
|
468
|
-
Platform : {active_platform: system | web | app | — nếu chưa xác định}
|
|
469
|
-
Service : {active_service} ({active_service_module}) [← domain{/platform}{/prd_slug} nếu route qua by_prd_slug] | multi (map-theo-platform hoặc map-theo-prd_slug, chốt khi target đủ platform/prd_slug) | single-service
|
|
470
|
-
Svc Root : {service_root} — đã nạp conventions + trace_dir từ config service | —
|
|
471
|
-
Status : {FULL | PARTIAL — thiếu: CLAUDE.md / business-dict / core-entities | MINIMAL}
|
|
205
|
+
Phạm vi: {all | domain={d} | prd={TICKET-ID} | uc={UC-ID}}
|
|
206
|
+
{n} PRD · {m} UC · {k} sổ → {ước lượng: toàn bộ repo | một phần}
|
|
472
207
|
```
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
208
|
+
*Không có dòng này thì người dùng không biết mình vừa gọi một lệnh cỡ nào — và đây là lệnh đắt nhất trong 33 lệnh (~33k token chỉ dẫn trước khi mở artifact nào).*
|
|
209
|
+
|
|
210
|
+
> **Vì sao step này là "nối dây", không phải "thêm tính năng" (GAPS-v4 G57).**
|
|
211
|
+
> Trước nó, **năm** chỗ trong lệnh này mô tả một *"domain argument"* / *"domain filter"* **không tồn
|
|
212
|
+
> tại**: ghi chú Gate (*"target là một tên domain hoặc UC-ID cụ thể từ `$ARGUMENTS`"*) · Step 1 đọc TSV
|
|
213
|
+
> *"khớp domain target"* · schema biên bản `"<domain argument, or 'all' if no filter>"` · Step 8
|
|
214
|
+
> *"nếu có domain filter, chỉ gồm các PRD đó"* · dòng `trace-history` mang field `domain`.
|
|
215
|
+
> Và `gate-trace` **đã** đọc `report.domain` rồi **chặn PR** nếu nó khác `all`.
|
|
216
|
+
>
|
|
217
|
+
> Nhưng Step 0 đặt `all_trace_dirs` = toàn bộ **vô điều kiện**, và chỗ duy nhất parse `$ARGUMENTS` là
|
|
218
|
+
> Step 5e cho hai cờ `--realign`. Nên ô đó **luôn** ghi `all`, và phần kiểm của gate **chưa bao giờ
|
|
219
|
+
> chạy một lần nào**.
|
|
220
|
+
>
|
|
221
|
+
> Đây đúng hình dạng **R1 fail build vì nó** — *"field có consumer mà không có producer"*, ca
|
|
222
|
+
> `@trace.sc_version` (3 consumer, 0 producer, sống qua nhiều version không ai bắt được). Nó sống
|
|
223
|
+
> được vì R1 chỉ canh field trong **sổ TSV** và tag trong **code**, không canh key ở cấp gốc **biên
|
|
224
|
+
> bản JSON**. `self-check` **R9(h)** giờ canh cả hai đầu.
|
|
225
|
+
>
|
|
226
|
+
> Và ghi chú Gate còn **tệ hơn im lặng** — nó gây nhầm: một agent đọc *"target là một tên domain hoặc
|
|
227
|
+
> UC-ID"* sẽ **tin rằng** scoping hoạt động.
|
|
491
228
|
|
|
492
229
|
---
|
|
493
|
-
|
|
494
|
-
## Process
|
|
495
|
-
|
|
496
230
|
### Step 0 — Umbrella Mode Detection
|
|
497
231
|
|
|
498
232
|
Kiểm tra mảng `services` có tồn tại trong `project-context.yaml` không.
|
|
@@ -517,6 +251,44 @@ Kiểm tra mảng `services` có tồn tại trong `project-context.yaml` không
|
|
|
517
251
|
|
|
518
252
|
---
|
|
519
253
|
|
|
254
|
+
### Step 1.0 — Lint sổ trace TRƯỚC khi đọc *(bắt buộc, không bỏ qua được)*
|
|
255
|
+
|
|
256
|
+
Chạy checker xác định trên mọi trace dir đã phân giải ở Step 0:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
npx @educa-corp/sdd-framework --lint-trace --trace {all_trace_dirs, ngăn cách bởi dấu phẩy} --specs {paths.specs_dir}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
*`bin/` sống trong package npm, không được cài vào project — nên `npx` là đường duy nhất. Không có mạng / npx fail → **bỏ qua step này**, in `⚠️ Chưa lint được sổ trace (npx không khả dụng) — kết quả dưới đây chưa được kiểm cấu trúc` vào report, rồi tiếp Step 1. Đừng để nó chặn cả lệnh.*
|
|
263
|
+
|
|
264
|
+
**Exit 0 → tiếp Step 1.**
|
|
265
|
+
|
|
266
|
+
**Exit 1 → DỪNG NGAY.** Đừng nạp, đừng tính `status`, đừng ghi lại gì:
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
🔴 SỔ TRACE HỎNG — không phán trạng thái trên dữ liệu này.
|
|
270
|
+
|
|
271
|
+
{nguyên văn output của lint-trace}
|
|
272
|
+
|
|
273
|
+
Vì sao dừng thay vì cố đọc tiếp: Step 3 tính lại `status` rồi Step 6 GHI NGƯỢC
|
|
274
|
+
vào TSV. Chạy tiếp trên một row đã lệch cột sẽ nướng cái lệch đó vào sổ vĩnh viễn —
|
|
275
|
+
và sổ trace là dữ liệu KHÔNG regenerate được.
|
|
276
|
+
|
|
277
|
+
Sửa:
|
|
278
|
+
1. Xem lần ghi nào làm hỏng : git log -p {file}
|
|
279
|
+
2. Sửa file (thường là thêm/bớt một dấu tab, hoặc giữ cả hai row sau merge)
|
|
280
|
+
3. Kiểm lại : npx @educa-corp/sdd-framework --lint-trace
|
|
281
|
+
4. Rồi chạy lại /validate-traces
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
> **Vì sao step này tồn tại (G38):** `bin/self-check.js` canh **contract** — nó đọc file lệnh
|
|
285
|
+
> và kiểm "lệnh có gọi đúng tên cột không". Nó không bao giờ mở một `.tsv` thật. Trong khi sổ
|
|
286
|
+
> 24 cột được ghi **bằng tay**, hàng chục lần mỗi feature. Một dấu tab thiếu ở ô 17 dồn mọi ô
|
|
287
|
+
> sau đó sang trái một bậc — ô 21 `status` nhận một ngày tháng — và **trước step này không gì
|
|
288
|
+
> báo lỗi**: lệnh đọc tiếp, in ra số, số chảy vào `trace-report.json` rồi vào dashboard.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
520
292
|
### Step 1 — Nạp dữ liệu TSV
|
|
521
293
|
|
|
522
294
|
**Umbrella mode:** đọc tất cả file `{trace_dir}/**/*.tsv` từ mọi dir trong `all_trace_dirs`. Với mỗi TSV, gắn tag row với tên service gốc.
|
|
@@ -539,6 +311,29 @@ Nếu version SC trong `.feature` khác `spec_ver` của `.tsv` → cập nhật
|
|
|
539
311
|
|
|
540
312
|
Cũng phát hiện SC có trong `.feature` (platform đó) nhưng thiếu trong `.tsv` → thêm row mới với `status: UNTRACKED`. *(sc_id trùng số giữa các platform là 2 scenario khác nhau → mỗi sổ platform giữ tập SC riêng, không dedupe chéo platform.)*
|
|
541
313
|
|
|
314
|
+
### Step 2c — Phân giải lại `service` từ config hiện tại *(G51)*
|
|
315
|
+
|
|
316
|
+
*Cùng tinh thần Step 2 với `spec_ver`: cột TSV là **cache**, `services:` trong `project-context.yaml`
|
|
317
|
+
là **nguồn**. Mỗi lần chạy, đối chiếu lại.*
|
|
318
|
+
|
|
319
|
+
Với mỗi row có `service` ∈ (`unrouted`, `unresolved`), tra lại `services:` theo
|
|
320
|
+
`domain` + `platform` (từ tên file sổ) + `prd_slug`:
|
|
321
|
+
|
|
322
|
+
| Kết quả tra | Hành động |
|
|
323
|
+
|---|---|
|
|
324
|
+
| Giờ **khớp** một entry | **Cập nhật `service` = path đó** (in memory, ghi lại ở Step 6). Không cần chạy lại `/generate-bdd`. |
|
|
325
|
+
| Vẫn không khớp | Giữ `unrouted` → gắn cờ 🟠 `SERVICE_UNROUTED` |
|
|
326
|
+
| Config vẫn sai cấu trúc | Giữ `unresolved` → cùng cờ, nhưng lý do khác (bug config, không phải chờ quyết) |
|
|
327
|
+
|
|
328
|
+
> **Vì sao lệnh này được ghi một cột do `/generate-bdd` sở hữu:** đây là **ngoại lệ có chủ ý** với luật
|
|
329
|
+
> *"mỗi cột một chủ"* (`rules/workflow.md` §Trace Contract), và nó **không vi phạm tinh thần** của luật:
|
|
330
|
+
> lệnh này **không ghi một giá trị mới** — nó chỉ **phân giải một placeholder mà `/generate-bdd` đã cố ý
|
|
331
|
+
> để lại**. Khai tường minh trong `bin/trace-schema.json`: `service.written_by = [generate-bdd, validate-traces]`.
|
|
332
|
+
>
|
|
333
|
+
> Đây là thứ làm sổ **tự lành**: architect thêm mapping → lần `/validate-traces` kế tiếp nâng
|
|
334
|
+
> `unrouted` → path. Không sửa tay, không sinh lại BDD. Không có bước này thì `unrouted` **đọng lại
|
|
335
|
+
> vĩnh viễn** — đúng bệnh `TBD` mà G1/G28 đã chỉ ra.
|
|
336
|
+
|
|
542
337
|
### Step 2b — Reverse audit (bắt tag mồ côi)
|
|
543
338
|
|
|
544
339
|
*Step 2 đi chiều **spec → code** (mỗi row TSV, SC đó implement tới đâu). Step này đi **chiều ngược** — bắt lớp lỗi mà Step 2 cấu trúc không thể thấy: code trỏ vào một scenario **không còn tồn tại**. Xảy ra khi gen lại BDD 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.*
|
|
@@ -573,6 +368,84 @@ Không tìm thấy tag mồ côi nào → bỏ qua im lặng.
|
|
|
573
368
|
|
|
574
369
|
> **Vì sao DRIFT xét trước GAP:** một scenario đã 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, chạy /dev-gen-test" còn `DRIFT` = "regenerate". Nếu GAP thắng, code lỗi thời bị bỏ qua và test lại sinh trên code cũ. UNTRACKED vẫn phải là Rule 1 để scenario chưa code (gen_ver `—`) không lọt vào DRIFT.
|
|
575
370
|
|
|
371
|
+
### Step 3.9 — Phát hiện sửa spec ngoài đường chính thức *(chạy TRƯỚC Step 4)*
|
|
372
|
+
|
|
373
|
+
*Contract: `bin/trace-schema.json` → `spec_edit_detection`. Cờ: `PRD_UNTRACKED_EDIT`.*
|
|
374
|
+
|
|
375
|
+
**Vì sao bước này đứng TRƯỚC Step 4.** Step 4 và mọi bước sau nó đều dựa trên một giả định
|
|
376
|
+
**chưa được kiểm**: *nhãn `Version` của PRD phản ánh đúng nội dung hiện tại của nó.* Nếu ai sửa nội
|
|
377
|
+
dung mà không bump nhãn thì giả định đó sai, và Step 4 sẽ phán *"version khớp ⇒ sạch"* trên một tài
|
|
378
|
+
liệu đã đổi. Kiểm cấu trúc drift trên một nhãn không còn đúng thì cũng vô nghĩa như G1 kiểm cấu trúc
|
|
379
|
+
một quyển sổ sắp mất — nên hỏi trước.
|
|
380
|
+
|
|
381
|
+
**Điểm mù mà nó bịt (GAPS-v4 G54).** Toàn bộ lưới an toàn của framework so **nhãn version**, không so
|
|
382
|
+
**nội dung** — không có một content hash nào ở đâu. Nên một PRD bị sửa tay là điểm mù **tuyệt đối**:
|
|
383
|
+
Step 4 thấy `PRD Version == prd_version` ⇒ sạch · `gate-trace` thấy report khớp sổ ⇒ PASS ·
|
|
384
|
+
`require-fresh-audit` thấy PR không chạm tag ⇒ không đòi audit. **Cả ba tầng xanh, và cả ba đúng theo
|
|
385
|
+
định nghĩa của chính chúng.**
|
|
386
|
+
|
|
387
|
+
#### Đọc mốc của lần audit trước
|
|
388
|
+
|
|
389
|
+
Đọc khối **`spec_baseline`** trong `trace-report.json` của lần chạy trước (path:
|
|
390
|
+
`{living_docs_dir}/trace-report.json`). Mỗi entry: `prd_path` · `sha_at_audit` · `version_at_audit`.
|
|
391
|
+
|
|
392
|
+
- Khối **vắng** (lần audit đầu, hoặc report sinh bởi version cũ hơn) → **bỏ qua so sánh**, chỉ **ghi
|
|
393
|
+
mốc mới** ở Step 6b. In một dòng: `ⓘ spec_baseline: lần đầu ghi mốc — check sửa-ngoài-đường bắt đầu có hiệu lực từ lần chạy sau.`
|
|
394
|
+
|
|
395
|
+
#### So — hai nguồn bằng chứng, cần cả hai
|
|
396
|
+
|
|
397
|
+
Với mỗi file PRD trong phạm vi, ở repo chứa `{paths.specs_dir}`:
|
|
398
|
+
|
|
399
|
+
| Nguồn | Lệnh | Bắt ca nào |
|
|
400
|
+
|---|---|---|
|
|
401
|
+
| **git diff** | `git -C {specs repo} diff --name-only {sha_at_audit}..HEAD -- {prd_path}` | sửa **đã commit** |
|
|
402
|
+
| **git status** | `git -C {specs repo} status --porcelain -- {prd_path}` | sửa **CHƯA commit** — ca thường gặp nhất, vì PO đang gõ |
|
|
403
|
+
|
|
404
|
+
Thiếu nguồn thứ hai là mù với cả một lớp ca: PO sửa xong, chưa commit, chạy audit — và audit nói sạch.
|
|
405
|
+
|
|
406
|
+
#### Phán
|
|
407
|
+
|
|
408
|
+
| Nội dung đổi? | `Version` hiện tại vs `version_at_audit` | Kết luận |
|
|
409
|
+
|:---:|---|---|
|
|
410
|
+
| **có** | **BẰNG NHAU** | 🔴 **`PRD_UNTRACKED_EDIT`** — có người sửa ngoài `/generate-prd` · `/extend-prd` · `/amend-prd` · `/refine-prd` · `/review-context` |
|
|
411
|
+
| có | khác | ✅ không cờ — đã đi đường chính thức. Step 4 tiếp quản bình thường |
|
|
412
|
+
| không | bất kỳ | ✅ không cờ |
|
|
413
|
+
|
|
414
|
+
**Không có báo oan:** ca duy nhất bật cờ là *"đổi nội dung, giữ nguyên nhãn"*. Sửa **và** bump
|
|
415
|
+
version thì `version != version_at_audit` ⇒ im.
|
|
416
|
+
|
|
417
|
+
#### Ca không kiểm được → nói rõ là đang mù
|
|
418
|
+
|
|
419
|
+
Không phải git repo · `sha_at_audit` không còn (history bị rewrite) · `git` không khả dụng →
|
|
420
|
+
**bỏ qua** check này và in:
|
|
421
|
+
```
|
|
422
|
+
⚠️ Chưa kiểm được sửa-ngoài-đường cho {n} PRD ({lý do}) — điểm mù G54 đang MỞ ở các file này.
|
|
423
|
+
```
|
|
424
|
+
**KHÔNG** bịa cờ, và **KHÔNG** im lặng. Im lặng là lựa chọn rẻ nhất và tệ nhất trong ba.
|
|
425
|
+
|
|
426
|
+
#### Đường ra — tự lành, cố ý KHÔNG có lệnh escape
|
|
427
|
+
|
|
428
|
+
Cách sửa đúng là **bump version + ghi một row changelog nêu UC bị ảnh hưởng** — tức đúng việc
|
|
429
|
+
`/amend-prd` làm hộ. Làm xong thì `version != version_at_audit` ⇒ cờ tự tắt, và logic `PRD_DRIFT`
|
|
430
|
+
bình thường tiếp quản (đúng, vì nội dung có đổi thật).
|
|
431
|
+
|
|
432
|
+
> **Vì sao KHÔNG có `--accept-edit`:** thêm nó là thêm một đường **dán nhãn lên thay đổi chưa ai
|
|
433
|
+
> xem** — đúng cái sai mà ba rào của `--realign` (Step 5e) tồn tại để chặn.
|
|
434
|
+
|
|
435
|
+
#### Vì sao cờ này KHÔNG nằm trong `gate.blocking`
|
|
436
|
+
|
|
437
|
+
Quyết định có chủ ý, ghi ở `spec_edit_detection.$comment`:
|
|
438
|
+
|
|
439
|
+
| | |
|
|
440
|
+
|---|---|
|
|
441
|
+
| `gate.blocking` nghĩa hẹp là **code đang hỏng** | Cờ này nói về **spec**; code có thể đang hoàn toàn đúng. R9(e) tồn tại để giữ đúng ranh giới đó |
|
|
442
|
+
| Nợ tồn khi mới bật | Mọi project đang chạy đều đã có PRD sửa tay ⇒ cờ chặn mới sẽ đỏ khắp nơi ở lần đầu ⇒ **người ta tắt cổng** ⇒ mất luôn 4 cờ 🔴 thật. Đó đúng là thất bại R9(e) được viết ra để chặn, chỉ đến bằng một cửa khác |
|
|
443
|
+
| Nhưng nó vẫn 🔴 | In mỗi lần chạy, có khối riêng trong report + counter trong `summary` — đủ để thấy, không đủ để làm tắt cổng |
|
|
444
|
+
|
|
445
|
+
Team nào đã dọn sạch nợ tồn thì tự thêm `prd_untracked_edit_count` vào `gate.blocking` (kèm `why`) —
|
|
446
|
+
`self-check` R13(e) canh việc đó.
|
|
447
|
+
|
|
448
|
+
---
|
|
576
449
|
### Step 4 — PRD version drift check
|
|
577
450
|
|
|
578
451
|
Với mỗi UC, so:
|
|
@@ -586,13 +459,43 @@ Nếu layer nào sau version PRD hiện tại → trích các changelog entry k
|
|
|
586
459
|
|
|
587
460
|
*PRD là tài liệu **cấp feature** phủ nhiều UC, nhưng version của nó là **một scalar**. Nên 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.*
|
|
588
461
|
|
|
589
|
-
Đọc các row `# Change Log` của PRD **từ version của layer cũ nhất tới hiện tại
|
|
462
|
+
Đọc các row `# Change Log` của PRD **từ version của layer cũ nhất tới hiện tại**. Mỗi row mang một `{changelog_scope}` — contract máy đọc, khai ở `bin/trace-schema.json` → `changelog_row_contract`; producer là `/refine-prd` Phase 3, `/extend-prd` Bước 6, `/review-context` Fix/Resume Phase 3, và **bắt buộc** ghi thông tin này chính vì mục đích ở đây. *(`/generate-bdd` Version Check đọc cùng dữ liệu.)*
|
|
463
|
+
|
|
464
|
+
**Dựng `affected_ucs` theo ba bước — KHÔNG bỏ bước 2:**
|
|
465
|
+
|
|
466
|
+
**1. Tách mệnh đề.** Mỗi row `{changelog_scope}` gồm các mệnh đề ngăn bằng `;`, mỗi mệnh đề mở đầu bằng đơn vị sở hữu: `{UC-ID}: {mô tả}` hoặc `PRD-global: {mô tả}`.
|
|
467
|
+
|
|
468
|
+
**2. Chuẩn hoá về UC — phép phân giải `BR/AC → UC sở hữu`.** Trong mỗi mệnh đề, ngoài UC-ID mở đầu còn có thể có BR/AC được nêu. Đưa **mọi** BR/AC về UC sở hữu **trước khi** so:
|
|
469
|
+
|
|
470
|
+
| Gặp | Phân giải thành |
|
|
471
|
+
|---|---|
|
|
472
|
+
| `BR{n}` | UC có `BR{n}` trong **bảng Business Rule** của nó (PRD §3) |
|
|
473
|
+
| `AC{n}` | UC có `AC{n}` ở dòng **`**AC liên quan:**`** của nó (PRD §3) |
|
|
474
|
+
| `PRD-global` | **không** thuộc UC nào — không thêm gì vào `affected_ucs` |
|
|
475
|
+
| BR/AC **không** phân giải được về UC nào *(ID đã bị xoá, hoặc PRD lệch cấu trúc)* | coi **cả row** là **mơ hồ** → hàng 3 dưới đây. **KHÔNG** bỏ qua im lặng mệnh đề đó |
|
|
476
|
+
|
|
477
|
+
*Không phát sinh I/O: Step 4 đã mở file PRD này ở đầu bước.*
|
|
478
|
+
|
|
479
|
+
**3. Phân loại từng UC** *(first-match-wins)*:
|
|
590
480
|
|
|
591
481
|
| Điều kiện | Cờ | Hành động |
|
|
592
482
|
|---|---|---|
|
|
593
|
-
|
|
|
594
|
-
| UC này **
|
|
595
|
-
|
|
|
483
|
+
| **Bất kỳ** row nào trong khoảng **mơ hồ** (không mệnh đề nào nêu được đơn vị sở hữu, hoặc bước 2 không phân giải được) | `PRD_DRIFT` 🟠 cho **MỌI** UC | Không suy đoán được thì quét rộng |
|
|
484
|
+
| UC này **có** trong `affected_ucs` | `PRD_DRIFT` 🟠 | Cần regen thật — theo bảng `drifted_layers` bên dưới |
|
|
485
|
+
| UC này có trong `affected_ucs` **CHỈ** qua (các) mệnh đề mang hậu tố **`[no-behavior]`** | `PRD_STALE_REF` ⓘ | Producer đã **chứng minh** thay đổi không đổi hành vi (chỉ thêm/bỏ vỏ cấu trúc). Xem `changelog_row_contract.neutral_checks` |
|
|
486
|
+
| UC này **không** có trong `affected_ucs`, **và** mọi row trong khoảng đều nêu rõ scope | `PRD_STALE_REF` ⓘ | Nội dung không đổi, chỉ con trỏ version cũ. **KHÔNG** route regen — dùng `--realign-prd-version` |
|
|
487
|
+
|
|
488
|
+
> **Vì sao bước 2 là bắt buộc (G53).** Bản cũ viết *"trích tập UC/AC/BR được nêu"* rồi so bằng phép thử *"**UC** này có trong tập?"*. Hai câu đó **không khớp nhau**: tập chứa lẫn UC, AC và BR, nhưng phép thử chỉ hỏi về UC. Nên một row như `thêm UC7: AC12-AC14; sửa BR8` cho tập `{UC7, AC12-14, BR8}` — và **UC3, chủ sở hữu BR8, không có trong đó**.
|
|
489
|
+
>
|
|
490
|
+
> Row đó nêu rất nhiều ID nên **không** rơi vào hàng "mơ hồ". Kết quả: UC3 → ⓘ *"không phải lỗi"*, trong khi BR mà nó sở hữu vừa đổi hành vi. Và ⓘ **mở cửa** cho `--realign-prd-version` (rào an toàn của nó chỉ **từ chối khi UC là 🟠**) ⇒ nhãn `prd_version` bị dán lại ở cả TSV lẫn tag code ⇒ **cờ sạch vĩnh viễn trên thay đổi chưa ai implement**.
|
|
491
|
+
>
|
|
492
|
+
> Đây là G1 đúng nghĩa — cờ **im lặng** — chỉ khác là lần này có thêm một lệnh tự động đóng dấu lên nó.
|
|
493
|
+
|
|
494
|
+
> **Vì sao hàng "mơ hồ" lên ĐẦU bảng.** Nó là điều kiện **cấp row**, không phải cấp UC: một row mơ hồ làm mọi phán đoán per-UC trong khoảng đó vô giá trị. Xét nó sau các hàng kia thì một UC có thể được xếp ⓘ **trước khi** ta biết là không suy đoán được gì — và ⓘ là hạng mở cửa cho `--realign`.
|
|
495
|
+
|
|
496
|
+
> **Hàng "mơ hồ" là lưới an toàn — hỏng theo hướng an toàn.** Changelog viết ẩu thì ta mất tính năng *lọc*, KHÔNG mất tính năng *cảnh báo*. Đồng bộ với `generate-bdd` Version Check: *"changelog row không nêu rõ scope (mơ hồ) → khuyến nghị F (gen lại toàn bộ)"*.
|
|
497
|
+
>
|
|
498
|
+
> ⚠️ **Nhưng lưới an toàn KHÔNG phải cái cớ để producer ghi bừa.** Nó đúng khi **thiếu** thông tin; nó sai khi producer **có** thông tin mà không ghi. Đó là G52: `/review-context --fix` từng ghi cứng `Auto-fix: applied {N} findings` — 0 scope — trong khi findings YAML của nó có `uc_id` bắt buộc cho từng finding. Một sửa từ trong UC5 làm **cả 8 UC** ăn 🟠. `self-check` R12 giờ fail build nếu producer nào không nhắc `{changelog_scope}`.
|
|
596
499
|
|
|
597
500
|
> **Hàng thứ ba là lưới an toàn — hỏng theo hướng an toàn.** Changelog viết ẩu thì ta mất tính năng *lọc*, KHÔNG mất tính năng *cảnh báo*. Đồng bộ với `generate-bdd` Version Check: *"changelog row không nêu rõ UC/AC/BR (mơ hồ) → khuyến nghị F (gen lại toàn bộ)"*.
|
|
598
501
|
>
|
|
@@ -622,13 +525,18 @@ Skip cột nào chưa có revision đã lưu (`—`), hoặc cả UC chưa có t
|
|
|
622
525
|
|
|
623
526
|
*Tech-doc có **đúng cùng hình dạng** với PRD: một doc **GỘP cấp PRD**, một `@trace.revision` chung cho nhiều UC. Chế độ **APPEND** (`generate-tech-docs` Bước 1) thêm UC mới vào doc đã có → revision bump → **mọi UC cũ lệch**, dù phần của chúng không đổi một dòng.*
|
|
624
527
|
|
|
625
|
-
Đọc **§10 UC Coverage** và **Changelog** của tech-doc,
|
|
528
|
+
Đọc **§10 UC Coverage** và **Changelog** của tech-doc. Mỗi row Changelog mang một `{changelog_scope}` cùng contract với PRD (`changelog_row_contract`); producer là `/generate-tech-docs` Bước 1b, đơn vị "global" ở đây tên là `doc-global` thay cho `PRD-global`.
|
|
529
|
+
|
|
530
|
+
Dựng `affected_ucs` **theo đúng ba bước của Step 4**, kể cả bước 2 (`BR/AC → UC sở hữu`) — tech-doc cũng nêu §/SC/BR trong mô tả, và một mệnh đề nêu `§5.9` mà bỏ UC thì UC đó rơi vào ⓘ y như ca BR8 ở Step 4. Rồi phân loại *(first-match-wins, cùng thứ tự)*:
|
|
626
531
|
|
|
627
532
|
| Điều kiện | Cờ |
|
|
628
533
|
|---|---|
|
|
629
|
-
|
|
|
630
|
-
| UC này **
|
|
631
|
-
|
|
|
534
|
+
| **Bất kỳ** row nào trong khoảng **mơ hồ** (không nêu được đơn vị sở hữu, hoặc bước 2 không phân giải được) | 🟠 cho **MỌI** UC (lưới an toàn) |
|
|
535
|
+
| UC này **có** trong `affected_ucs` | `TECHDOC_DRIFT` / `FE_TECHDOC_DRIFT` 🟠 |
|
|
536
|
+
| UC này có trong `affected_ucs` **CHỈ** qua mệnh đề mang hậu tố `[no-behavior]` | `TECHDOC_STALE_REF` ⓘ |
|
|
537
|
+
| UC này **không** có trong `affected_ucs`, mọi row nêu rõ scope | `TECHDOC_STALE_REF` ⓘ — dùng `--realign-techdoc-revision` |
|
|
538
|
+
|
|
539
|
+
> **`doc-global` là đường ra bình thường cho tech-doc, không phải ngoại lệ.** Sửa §11 Cross-cutting hay §2 kiến trúc chung thì không mệnh đề nào nêu UC ⇒ `affected_ucs` rỗng ⇒ mọi UC ở lại ⓘ. Nên `/generate-tech-docs` **không cần** dùng `[no-behavior]`; marker đó dành cho producer biết chính xác `check_id` của từng fix (`/review-context --fix`). Consumer vẫn phải **hiểu** marker vì cùng một hàng bảng phục vụ cả hai artifact.
|
|
632
540
|
|
|
633
541
|
### Step 5e — Realign mode *(chỉ chạy khi có flag)*
|
|
634
542
|
|
|
@@ -744,6 +652,22 @@ Với mỗi file `.tsv` đã xử lý: ghi `spec_ver`, `status`, `last_updated`
|
|
|
744
652
|
Và **đồng bộ `prd_status` ← `| **Status** |`** của PRD tương ứng (`{paths.specs_dir}/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md`) — đối xứng với `uc_status`: PRD Metadata là nguồn-sự-thật về duyệt PRD. Không có bước này thì `prd_status` là **write-once** (chỉ `/generate-bdd` ghi một lần) và sẽ giữ `approved` vĩnh viễn sau khi `/refine-prd` hay `/review-context --fix` reset PRD về `draft`. *(Step 4 đã đọc file PRD này rồi — không phát sinh I/O.)*
|
|
745
653
|
**Đừng** sửa `dev_selftest`/`dev_selftest_at` (do `/dev-run-test` sở hữu) hay `qc_status`/`qc_run_at`/`qc_owner`/`qc_blocked_by` (do `/qc-run-test` + `/report-bug` sở hữu); lệnh này chỉ đọc chúng cho report.
|
|
746
654
|
|
|
655
|
+
### Step 6b — Ghi mốc `spec_baseline` cho lần audit sau
|
|
656
|
+
|
|
657
|
+
*Đây là **nửa GHI** của check ở Step 3.9. Thiếu nó thì cờ `PRD_UNTRACKED_EDIT` **không bao giờ bật** — và mọi rule khác vẫn ✅, vì R6 chỉ canh "giá trị enum có xuất hiện" và R7 chỉ canh "cờ có counter". `self-check` R13 canh đúng nửa này.*
|
|
658
|
+
|
|
659
|
+
Với **mỗi** file PRD trong phạm vi lần chạy này, ghi một entry vào khối `spec_baseline` của `trace-report.json` (Step 8):
|
|
660
|
+
|
|
661
|
+
| Key | Giá trị |
|
|
662
|
+
|---|---|
|
|
663
|
+
| `prd_path` | path tương đối tới file PRD trong specs repo |
|
|
664
|
+
| `sha_at_audit` | `git -C {specs repo} rev-parse HEAD` — commit tại thời điểm audit |
|
|
665
|
+
| `version_at_audit` | `\| **Version** \|` hiện tại của PRD |
|
|
666
|
+
|
|
667
|
+
Không phải git repo / `git` không khả dụng → ghi `sha_at_audit: null` và **vẫn ghi** `version_at_audit` (lần sau Step 3.9 sẽ báo đang mù, không im lặng).
|
|
668
|
+
|
|
669
|
+
> **Ghi mốc là thao tác cuối, sau khi đã phán xong.** Ghi trước thì một lần chạy bị ngắt giữa đường sẽ để lại mốc mới mà chưa phán gì — và lần sau so với mốc đó thì thay đổi trong khoảng đó **biến mất khỏi tầm quan sát vĩnh viễn**.
|
|
670
|
+
|
|
747
671
|
### Step 7 — Tính aggregate cho dashboard
|
|
748
672
|
|
|
749
673
|
```
|
|
@@ -768,6 +692,9 @@ fe_integrated = rows where fe_phase == integrated # FE đã wire adapter th
|
|
|
768
692
|
# công việc CHƯA XONG dù status có thể đã là OK (có code + có test trên mock).
|
|
769
693
|
orphaned_count = rows where status == ORPHANED # code còn, scenario đã bị xoá khỏi .feature (Step 2b/Rule 0)
|
|
770
694
|
trace_orphan_count = số tag @trace.implements/@trace.verifies trỏ vào SC không tồn tại VÀ không có row TSV (Step 2b)
|
|
695
|
+
prd_untracked_edit_count = số file PRD có nội dung đổi kể từ `sha_at_audit` mà `Version` KHÔNG đổi
|
|
696
|
+
(Step 3.9). 🔴 — có người sửa ngoài đường chính thức, nên MỌI phán đoán version
|
|
697
|
+
của Step 4/5 trên file đó đang dựa vào một nhãn không còn đúng.
|
|
771
698
|
prd_drift_count = số UC bị cờ PRD_DRIFT (lệch version VÀ changelog nêu UC này — Step 4)
|
|
772
699
|
prd_stale_ref_count = số UC bị cờ PRD_STALE_REF (lệch version nhưng changelog KHÔNG nêu UC này —
|
|
773
700
|
nội dung không đổi, chỉ con trỏ cũ). ⓘ không phải lỗi; sạch bằng --realign-prd-version
|
|
@@ -782,10 +709,28 @@ by_service = map {service → {total_scs, coded_scs, tested_scs, drift_cou
|
|
|
782
709
|
# Trả lời câu số MỘT của dự án nhiều đội: "đội nào còn bao nhiêu việc".
|
|
783
710
|
# Trước khi có cột 23, trace gộp (spec_source) KHÔNG mang thông tin sở hữu ở
|
|
784
711
|
# cấp row nên câu này không trả lời được. Bỏ qua map này ở single-service.
|
|
712
|
+
by_platform = map {platform → {total_scs, coded_scs, tested_scs, drift_count}} — gom theo
|
|
713
|
+
platform (lấy từ TÊN FILE sổ `{UC-ID}-{platform}.tsv`, cùng nguồn với field
|
|
714
|
+
`platform` của mỗi scenario ở Step 8)
|
|
715
|
+
# CHỈ tạo ô cho platform THỰC SỰ có scenario — dự án chỉ có `web` thì chỉ một ô.
|
|
716
|
+
# Trả lời "web xong bao nhiêu %, system xong bao nhiêu %" — câu thường ngày khi
|
|
717
|
+
# làm FE và BE song song. Trước đó KHÔNG trả lời được từ `summary`: `by_service`
|
|
718
|
+
# là bảng chia nhóm DUY NHẤT, mà cột `service` là `—` ở mọi row của dự án
|
|
719
|
+
# single-service ⇒ nó gộp tất cả vào MỘT ô, và platform hoàn toàn vô hình.
|
|
720
|
+
# Đây là hình dạng của G33: dữ liệu có ở cấp row (G48 vừa thêm `platform` vào
|
|
721
|
+
# từng scenario) nhưng KHÔNG có ô tổng ⇒ dashboard chỉ đọc `summary` thì mù.
|
|
722
|
+
# Bắt dashboard tự duyệt prds[].ucs[].scenarios[] mà cộng lại chính là cái bẫy
|
|
723
|
+
# G33 đã chỉ ra: người viết dashboard đọc `summary`, thấy đủ, rồi tưởng xong.
|
|
724
|
+
# KHÔNG thay `by_service` — hai TRỤC khác nhau, cùng hữu ích ở umbrella nhiều đội.
|
|
785
725
|
seam_unwired_count = số seam bị cờ SEAM_UNWIRED (hàng thật đã có nhưng consumer còn wire vào stub — Step 5b)
|
|
786
726
|
seam_pending_count = số seam bị cờ SEAM_PENDING (owner UC chưa gen — ⓘ chưa phải lỗi; PM dùng để xếp thứ tự gen)
|
|
787
727
|
stub_unresolved_count = số stub bị cờ STUB_UNRESOLVED (method còn trắng dù owner đã gen / có hàm song song — Step 5b)
|
|
788
728
|
stub_pending_count = số stub bị cờ STUB_PENDING (owner BDD chưa gen — ⓘ chưa phải lỗi)
|
|
729
|
+
service_unrouted_count = số row có `service` ∈ (unrouted, unresolved) SAU khi đã phân giải lại ở
|
|
730
|
+
Step 2c. 🟠 KHÔNG chặn PR — "chưa ai quyết repo" là trạng thái hợp lệ ở feature
|
|
731
|
+
đầu tiên của một domain mới, không phải code hỏng. Nhưng phải NHÌN THẤY ĐƯỢC:
|
|
732
|
+
không có counter thì `unrouted` đọng lại vĩnh viễn và `by_service` có một ô rác
|
|
733
|
+
mà không ai để ý — đúng bệnh `TBD` (G51).
|
|
789
734
|
# LUẬT (rules/workflow.md §Trace Contract): MỌI giá trị trong vocabularies.audit_flags phải có
|
|
790
735
|
# một counter {flag_lowercase}_count ở đây VÀ trong summary của JSON. bin/self-check.js R7 ép
|
|
791
736
|
# điều này — thiếu counter = cờ không quan sát được ở tầng tổng hợp, dashboard không thấy.
|
|
@@ -829,7 +774,11 @@ Schema:
|
|
|
829
774
|
```json
|
|
830
775
|
{
|
|
831
776
|
"generated_at": "<ISO-8601 timestamp>",
|
|
832
|
-
"
|
|
777
|
+
"scope": {
|
|
778
|
+
"kind": "all | domain | prd | uc",
|
|
779
|
+
"value": "<giá trị scope, hoặc 'all'>"
|
|
780
|
+
},
|
|
781
|
+
"domain": "<domain trong scope, hoặc 'all'>",
|
|
833
782
|
"summary": {
|
|
834
783
|
"total_prds": 0,
|
|
835
784
|
"approved_prds": 0,
|
|
@@ -848,6 +797,7 @@ Schema:
|
|
|
848
797
|
"fe_integrated": 0,
|
|
849
798
|
"orphaned_count": 0,
|
|
850
799
|
"trace_orphan_count": 0,
|
|
800
|
+
"prd_untracked_edit_count": 0,
|
|
851
801
|
"prd_drift_count": 0,
|
|
852
802
|
"prd_stale_ref_count": 0,
|
|
853
803
|
"bdd_drift_count": 0,
|
|
@@ -861,6 +811,7 @@ Schema:
|
|
|
861
811
|
"seam_pending_count": 0,
|
|
862
812
|
"stub_unresolved_count": 0,
|
|
863
813
|
"stub_pending_count": 0,
|
|
814
|
+
"service_unrouted_count": 0,
|
|
864
815
|
"dev_selftest_passing": 0,
|
|
865
816
|
"dev_selftest_failing": 0,
|
|
866
817
|
"dev_selftest_not_run": 0,
|
|
@@ -875,6 +826,11 @@ Schema:
|
|
|
875
826
|
"<service path, e.g. user-service>": {
|
|
876
827
|
"total_scs": 0, "coded_scs": 0, "tested_scs": 0, "drift_count": 0
|
|
877
828
|
}
|
|
829
|
+
},
|
|
830
|
+
"by_platform": {
|
|
831
|
+
"<web | app | system — CHỈ platform thực sự có scenario>": {
|
|
832
|
+
"total_scs": 0, "coded_scs": 0, "tested_scs": 0, "drift_count": 0
|
|
833
|
+
}
|
|
878
834
|
}
|
|
879
835
|
},
|
|
880
836
|
"prds": [
|
|
@@ -894,6 +850,7 @@ Schema:
|
|
|
894
850
|
"scenarios": [
|
|
895
851
|
{
|
|
896
852
|
"sc_id": "<e.g. PAY-UC01-SC1>",
|
|
853
|
+
"platform": "web | app | system",
|
|
897
854
|
"sc_title": "<title>",
|
|
898
855
|
"spec_ver": "<current version from .feature>",
|
|
899
856
|
"gen_ver": "<version at codegen time>",
|
|
@@ -921,7 +878,24 @@ Schema:
|
|
|
921
878
|
]
|
|
922
879
|
}
|
|
923
880
|
],
|
|
881
|
+
"spec_baseline": [
|
|
882
|
+
{
|
|
883
|
+
"prd_path": "<specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md>",
|
|
884
|
+
"sha_at_audit": "<git rev-parse HEAD của specs repo, hoặc null nếu không phải git repo>",
|
|
885
|
+
"version_at_audit": "<Version của PRD tại thời điểm audit>"
|
|
886
|
+
}
|
|
887
|
+
],
|
|
924
888
|
"issues": {
|
|
889
|
+
"prd_untracked_edit": [
|
|
890
|
+
{
|
|
891
|
+
"prd_path": "<specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md>",
|
|
892
|
+
"version": "<Version hiện tại — KHÔNG đổi kể từ lần audit>",
|
|
893
|
+
"sha_at_audit": "<commit lần audit trước>",
|
|
894
|
+
"evidence": "git diff | git status | cả hai",
|
|
895
|
+
"affected_ucs": ["<mọi UC của PRD này — không suy đoán được ai bị đụng>"],
|
|
896
|
+
"fix": "bump Version + ghi row changelog nêu UC bị ảnh hưởng (đó là việc /amend-prd làm hộ). KHÔNG có --accept-edit: dán nhãn lên thay đổi chưa ai xem là đúng cái rào của --realign tồn tại để chặn."
|
|
897
|
+
}
|
|
898
|
+
],
|
|
925
899
|
"drift": [
|
|
926
900
|
{
|
|
927
901
|
"sc_id": "<SC-ID>",
|
|
@@ -1060,6 +1034,16 @@ Schema:
|
|
|
1060
1034
|
"fix": "Trỏ binding của <consumer_uc> sang <RealClass> (xoá/thay stub), build lại"
|
|
1061
1035
|
}
|
|
1062
1036
|
],
|
|
1037
|
+
"service_unrouted": [
|
|
1038
|
+
{
|
|
1039
|
+
"sc_id": "<SC-ID>",
|
|
1040
|
+
"platform": "web | app | system",
|
|
1041
|
+
"domain": "<domain của PRD>",
|
|
1042
|
+
"value": "unrouted | unresolved",
|
|
1043
|
+
"reason": "<lý do context-loader đã ghi — vd: domain chưa có entry trong services:>",
|
|
1044
|
+
"fix": "thêm mapping cho domain <domain> vào services: của .agent/project-context.yaml, rồi chạy lại /validate-traces (nó tự nâng unrouted → path). KHÔNG cần sinh lại BDD."
|
|
1045
|
+
}
|
|
1046
|
+
],
|
|
1063
1047
|
"stub_unresolved": [
|
|
1064
1048
|
{
|
|
1065
1049
|
"artifact": "<ClassName#method>",
|
|
@@ -1075,6 +1059,11 @@ Schema:
|
|
|
1075
1059
|
```
|
|
1076
1060
|
|
|
1077
1061
|
**Rules:**
|
|
1062
|
+
- **`by_platform` là bắt buộc** (nếu có ít nhất một scenario). Cùng hình dạng `by_service`, khoá **động** — một ô cho mỗi platform tìm thấy, không phải một ô cố định cho mỗi giá trị vocabulary. Thêm platform thứ tư vào vocabulary thì nó tự có ô, không cần sửa gì ở đây.
|
|
1063
|
+
> Đây là lý do `by_platform` **không cần** một rule `self-check` riêng: khác cờ audit (mỗi cờ cần một counter mang tên riêng, nên R7 phải canh từng cái), ở đây không có gì để lệch.
|
|
1064
|
+
- **`platform` (bắt buộc, mỗi scenario):** lấy từ **tên file sổ** `{UC-ID}-{platform}.tsv` — Step 2 đã đọc nó để tìm đúng `.feature`. Giá trị: `web` | `app` | `system`.
|
|
1065
|
+
> **Vì sao bắt buộc (G48):** `sc_id` **một mình không định danh được** một scenario. Chính Step 2 phát biểu điều đó: *"sc_id trùng số giữa các platform là 2 scenario khác nhau"*. Sổ TSV giải quyết bằng tên file; JSON thì làm phẳng mọi platform vào chung một cây `scenarios[]`, nên thiếu field này thì `AUTH-UC1-SC1` của web và của app **không phân biệt được** — panel hiện trùng lặp hoặc đè nhau, và không ai trả lời được *"SC1 của app xong chưa"*.
|
|
1066
|
+
> Bất đối xứng cũ: `issues.orphaned[]` và `issues.fe_techdoc_drift[]` **đã** mang `platform`; chỉ cây dữ liệu chính là không.
|
|
1078
1067
|
- `implemented_by`: dùng `null` (không phải `"—"`) trong JSON khi không có giá trị
|
|
1079
1068
|
- `test_count`: dùng integer `0` (không phải `"—"`) khi không có test
|
|
1080
1069
|
- `test_classes`: dùng `[]` (không phải `"—"`) khi không có test class
|
|
@@ -1084,7 +1073,11 @@ Schema:
|
|
|
1084
1073
|
Row `ORPHANED` xuất ra JSON là: `"status": "DRIFT"` + `"orphaned": true`. Panel chưa hỗ trợ vẫn hiện nó như `DRIFT` — đủ đúng về nghĩa ("code không khớp spec, cần xử lý") và **không im lặng**; panel có đọc `orphaned` thì hiện nhãn riêng. Chi tiết đầy đủ luôn có ở `orphaned[]` và ở report terminal.
|
|
1085
1074
|
**TSV giữ nguyên chữ `ORPHANED`** trong cột `status` — TSV là nguồn-sự-thật, JSON chỉ là bản xuất cho panel.
|
|
1086
1075
|
- `orphaned` (boolean): `true` chỉ khi cột `status` của TSV là `ORPHANED`; mọi row khác ghi `false` (đừng bỏ trống — panel đọc field vắng dễ ra `undefined`).
|
|
1087
|
-
- Luôn ghi vào `{paths.trace_dir}/trace-report.json` bất kể
|
|
1076
|
+
- Luôn ghi vào `{paths.trace_dir}/trace-report.json` bất kể phạm vi — nếu có scope, chỉ gồm các PRD/UC đó trong `prds[]`, và ghi **cả hai** field:
|
|
1077
|
+
- **`scope`** = `{kind, value}` từ Step 0-A. Đây là field `gate-trace` dùng để quyết chặn — xem dưới.
|
|
1078
|
+
- **`domain`** = domain trong scope (`--domain` → chính nó · `--prd`/`--uc` → domain phân giải được · không scope → `all`). Giữ cho **tương thích ngược** với `gate-trace` bản cũ.
|
|
1079
|
+
|
|
1080
|
+
> ⚠️ **Biên bản có scope KHÔNG BAO GIỜ được coi là biên bản đầy đủ.** `gate-trace` G2 fail nếu `scope.kind !== "all"`, **không ngoại lệ** — nó không nhìn xem trên đĩa có bao nhiêu domain. Vì sao tuyệt đối: bản cũ hỏi *"còn domain nào khác không"*, nên trong repo **một domain** thì `others` là **rỗng** ⇒ không fail ⇒ một biên bản hẹp-theo-PRD được nhận là *"toàn bộ"*. Đó đúng là *"cấp giấy xanh cho thứ chưa ai xem"* mà chú thích của chính gate cảnh báo. Thêm cờ scope mà không siết G2 là biến cổng thành **sân khấu** — đúng cái G39 dựng lên để chống.
|
|
1088
1081
|
- **TSV `"—"` mapping**: khi đọc file TSV, map giá trị dash sang kiểu JSON: `implemented_by: "—"` → `null`; `test_count: "—"` → `0`; `test_classes: "—"` → `[]`; `tech_doc_revision: "—"` → `0`; `fe_tech_doc_revision: "—"` → `0`; `dev_selftest: "—"` → `"not_run"`; `dev_selftest_at: "—"` → `null`; `qc_status: "—"` → `"not_run"`; `qc_run_at: "—"` → `null`; `qc_owner: "—"` → `null`; `qc_blocked_by: "—"` → `null`; `service: "—"` → `null`; `design_spec_version: "—"` → `null`
|
|
1089
1082
|
- **Backward-compat:** TSV cũ có thể thiếu cột mới hơn trong header — coi cột vắng nào là giá trị rỗng của nó (**đừng báo lỗi, đừng bỏ qua cả file**): `qc_owner`/`qc_blocked_by` (pre-19-col) → `null`; `fe_tech_doc_revision` (pre-22-col) → `0`; `service`/`design_spec_version` (pre-24-col) → `null`. Lần `/generate-bdd` gen lại tiếp theo nâng header lên layout **24 cột** hiện tại.
|
|
1090
1083
|
> **Đọc theo TÊN CỘT ở header row, KHÔNG theo vị trí.** Header là dòng đầu mỗi `.tsv` — parse nó rồi tra theo tên. Đếm vị trí sẽ vỡ ở đúng file cũ mà luật này sinh ra để đỡ. Header thiếu hoàn toàn (file hỏng) → mới báo lỗi cho file đó và đi tiếp, không abort cả lệnh.
|
|
@@ -1150,11 +1143,12 @@ mỗi scenario row mang service sở hữu ở **cột `service`** (cột 23, do
|
|
|
1150
1143
|
|
|
1151
1144
|
**Rotate:** file vượt **2000 dòng** → đổi tên thành `trace-history.{YYYY-MM}.jsonl` rồi bắt đầu file mới. Đừng xoá.
|
|
1152
1145
|
|
|
1153
|
-
**
|
|
1146
|
+
**Năm ràng buộc — đây là phần dễ làm sai:**
|
|
1154
1147
|
|
|
1155
1148
|
| Ràng buộc | Vì sao |
|
|
1156
1149
|
|---|---|
|
|
1157
1150
|
| Ghi **CHỈ** vào `{paths.trace_dir}` (nơi authoritative). **KHÔNG** copy sang `{panel_mirror}` hay `{living_docs_dir}` | Nó là dữ liệu tích luỹ, không phải thứ regenerate được. Nhân bản nó ra chỗ sinh-ra là tạo hai lịch sử lệch nhau. |
|
|
1151
|
+
| Dòng vừa append **PHẢI kết thúc bằng newline** — file không bao giờ được kết thúc giữa dòng | File này là append-only và được merge bằng `merge=union` (xem `{paths.trace_dir}/.gitattributes`). Thiếu newline cuối thì lần append sau — hoặc một lần union merge — **nối hai bản ghi JSON thành một dòng**, và dòng đó không parse được. `--lint-trace` T8 bắt, nhưng đây là ca phòng được bằng một ký tự. |
|
|
1158
1152
|
| File này **PHẢI được commit** cùng TSV | Nó là **dữ liệu**, không phải mirror. Regenerate lại không được — mất là mất vĩnh viễn. ⚠️ Đừng để nó dính vào luật gitignore của `.living-docs/` hay panel mirror; hai cái đó là bản sinh ra, cái này thì không. |
|
|
1159
1153
|
| **Không đụng** TSV và `trace-report.json` | TSV là bảng **trạng thái** — giữ nó phẳng. Lịch sử là file riêng, format riêng, vòng đời riêng. `trace-report.json` là contract với panel VS Code. |
|
|
1160
1154
|
| **Không lệnh nào được ra quyết định dựa trên file này** | Nó để **quan sát**, không phải để gác cổng. Một cái cổng phụ thuộc file có thể bị xoá là cổng dở. Cổng chặn PR vẫn chỉ là 4 cờ 🔴. |
|
|
@@ -1163,109 +1157,8 @@ Ghi thất bại (không có quyền, đĩa đầy) → **cảnh báo mềm mộ
|
|
|
1163
1157
|
|
|
1164
1158
|
## Output
|
|
1165
1159
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
Mọi report của lệnh phải kết thúc bằng section footer chuẩn này.
|
|
1169
|
-
|
|
1170
|
-
## Status Badge
|
|
1171
|
-
|
|
1172
|
-
Chọn một theo kết quả:
|
|
1173
|
-
- `✅ Complete` — mọi bước thành công, không có vấn đề
|
|
1174
|
-
- `❌ Failed` — lệnh không hoàn thành được do lỗi chặn
|
|
1175
|
-
- `⚠️ Warnings` — hoàn thành nhưng có vấn đề không chặn, nên review lại
|
|
1176
|
-
|
|
1177
|
-
## Output Artifacts
|
|
1178
|
-
|
|
1179
|
-
Liệt kê mọi file được tạo hoặc sửa bởi lệnh này:
|
|
1180
|
-
```
|
|
1181
|
-
Output Artifacts:
|
|
1182
|
-
{created|updated} {file-path} ({mô tả ngắn})
|
|
1183
|
-
{created|updated} {file-path} ({mô tả ngắn})
|
|
1184
|
-
```
|
|
1185
|
-
|
|
1186
|
-
Nếu không ghi file nào (vd: lệnh review hoặc phân tích) → ghi `Output Artifacts: none (read-only)`.
|
|
1187
|
-
|
|
1188
|
-
## Pipeline Position
|
|
1189
|
-
|
|
1190
|
-
In một sơ đồ pipeline một dòng, đánh dấu phase của lệnh HIỆN TẠI bằng `◀ bạn ở đây`,
|
|
1191
|
-
để người dùng luôn thấy lệnh này nằm ở đâu trong luồng end-to-end:
|
|
1192
|
-
|
|
1193
|
-
```
|
|
1194
|
-
Discovery → PRD → [Design Spec] → BDD → Tech Design → Code → Dev Self-Check → QC → Trace Audit
|
|
1195
|
-
```
|
|
1196
|
-
|
|
1197
|
-
Tìm lệnh hiện tại trong bảng phase dưới đây và đánh dấu **phase của nó** trong sơ đồ trên:
|
|
1198
|
-
|
|
1199
|
-
| Phase | Commands |
|
|
1200
|
-
|-------|----------|
|
|
1201
|
-
| Discovery | `/define-product` |
|
|
1202
|
-
| PRD | `/generate-prd` · `/extend-prd` · `/refine-prd` · `/review-context` (PRD) |
|
|
1203
|
-
| Design Spec | `/generate-design-spec` |
|
|
1204
|
-
| BDD | `/generate-bdd` · `/review-context` (BDD) |
|
|
1205
|
-
| Tech Design | `/generate-tech-docs` · `/map-testids` · `/review-tech-docs` |
|
|
1206
|
-
| Code | `/generate-code` · `/review-code` |
|
|
1207
|
-
| Dev Self-Check | `/dev-gen-test` · `/dev-run-test` · `/dev-smoke-test` |
|
|
1208
|
-
| QC | `/qc-analyze` · `/qc-plan` · `/qc-design-test` · `/qc-review` · `/qc-run-test` · `/qc-report` |
|
|
1209
|
-
| Trace Audit | `/validate-traces` |
|
|
1210
|
-
|
|
1211
|
-
Với **lệnh review**, thêm vòng review 3 bước và đánh dấu bước hiện tại, vd:
|
|
1212
|
-
`Vòng review: [① phân tích ◀] → ② Review Board → ③ --resume`.
|
|
1213
|
-
|
|
1214
|
-
**Lệnh xuyên suốt** (`/sync`, `/update-framework`, `/fix-bug`, `/debug`, `/learn`,
|
|
1215
|
-
`/report-bug`, `/propose-scenario`, `/generate-spec-manifest`) nằm ngoài pipeline tuyến tính —
|
|
1216
|
-
**bỏ hẳn dòng Pipeline** cho các lệnh này (đừng cố nhét chúng vào sơ đồ).
|
|
1217
|
-
|
|
1218
|
-
## Gợi ý lệnh tiếp theo
|
|
1219
|
-
|
|
1220
|
-
Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
|
|
1221
|
-
|
|
1222
|
-
| Lệnh hiện tại | Gợi ý lệnh tiếp theo |
|
|
1223
|
-
|-------------------------|-----------------------------------------------|
|
|
1224
|
-
| /setup-ai-first | `/define-product` để bắt đầu feature đầu tiên |
|
|
1225
|
-
| /define-product | `/generate-prd {product-definition-file}` |
|
|
1226
|
-
| /generate-prd | `/refine-prd {prd-file}` rồi `/review-context {prd-file}` |
|
|
1227
|
-
| /extend-prd | `/refine-prd {prd-file}` (soi phần vừa thêm) rồi `/review-context {prd-file}` → PO duyệt → `/generate-bdd` **chỉ cho UC MỚI**; UC cũ dùng `/validate-traces --realign-prd-version {UC-ID}` |
|
|
1228
|
-
| /refine-prd | Mở Review Board → cập nhật PRD → `/review-context {prd-file}` |
|
|
1229
|
-
| /review-context (PRD) | Khi 0 critical → PO đặt `Status: approved`, rồi FE/App: `/generate-design-spec {prd-file}` (→ design sign-off → BDD); BE: `/generate-bdd {prd-file}`. Còn critical/NEEDS_FIX → sửa PRD (giữ draft) |
|
|
1230
|
-
| /generate-design-spec | Designer review → xác nhận link Figma → PO + Designer sign-off → `/generate-bdd {prd-file}` |
|
|
1231
|
-
| /generate-bdd | `/review-context {feature-file}` để kiểm tra độ phủ |
|
|
1232
|
-
| /review-context (BDD) | `/generate-tech-docs {UC-ID}` nếu APPROVED; sinh lại nếu NEEDS_FIX |
|
|
1233
|
-
| /qc-analyze | `/qc-plan {UC-ID}` (xử lý các gap blocker 🔴 trước) |
|
|
1234
|
-
| /qc-plan | `/qc-design-test {UC-ID}` |
|
|
1235
|
-
| /qc-design-test | `/qc-review {UC-ID}` (review test-case) |
|
|
1236
|
-
| /qc-review (test-case) | `/qc-run-test {UC-ID}` nếu APPROVED; sửa TC nếu NEEDS_FIX |
|
|
1237
|
-
| /qc-run-test | `/qc-report {UC-ID}` rồi `/qc-review {UC-ID}` (review script) |
|
|
1238
|
-
| /qc-review (script) | `/qc-report {UC-ID}` rồi tạo PR nếu APPROVED |
|
|
1239
|
-
| /qc-report | `/validate-traces {UC-ID}` để làm mới Living Docs (qc_status) |
|
|
1240
|
-
| /map-testids | `/qc-design-test {UC-ID}` (QC dựng Page Object từ contract §4.5.6 vừa ghi) |
|
|
1241
|
-
| /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
|
|
1242
|
-
| /review-tech-docs | `/generate-code {feature-file}` nếu APPROVED; sửa doc nếu NEEDS_FIX |
|
|
1243
|
-
| /generate-code | Lần gen đầu → `/review-code {UC-ID}`; gen lại → `/dev-gen-test {UC-ID}` |
|
|
1244
|
-
| /dev-gen-test | `/dev-run-test {UC-ID}` |
|
|
1245
|
-
| /dev-run-test (passing) | `/review-code {UC-ID}` |
|
|
1246
|
-
| /dev-run-test (failing) | `/fix-bug {ticket-id}` hoặc `/debug {error}` |
|
|
1247
|
-
| /review-code | `/dev-smoke-test {UC-ID}` hoặc tạo PR |
|
|
1248
|
-
| /dev-smoke-test | Tạo PR và link tới ticket |
|
|
1249
|
-
| /validate-traces | **Cờ 🔴 trước (chặn PR):** SEAM_UNWIRED → nối binding sang class thật, xoá/thay stub · STUB_UNRESOLVED → `/generate-code {owner_uc}` (lấp logic tại chỗ + xoá hàm song song) · ORPHANED/TRACE_ORPHAN → quyết định thủ công (xoá code+test, đưa scenario trở lại `.feature`, hoặc sửa `sc_id` của tag). **Rồi:** DRIFT/UNTRACKED → `/generate-code {UC-ID}` · BDD_DRIFT → `/generate-code {feature-file}` · tech-doc lỗi thời vs BDD → `/generate-tech-docs` → `/review-tech-docs` · PRD drift → `/generate-bdd {prd-file}` · GAP → `/dev-gen-test {UC-ID}`. **Chỉ tạo PR khi mọi cờ 🔴 = 0** |
|
|
1250
|
-
| /fix-bug | `/dev-run-test {UC-ID}` (dev_selftest vừa reset về not_run) → tạo PR; nếu fix một `{BUG-ID}` → QC chạy `/qc-run-test {UC-ID}` để verify + đóng bug |
|
|
1251
|
-
| /debug | `/fix-bug {ticket-id}` nếu cần sửa |
|
|
1252
|
-
| /report-bug | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
|
|
1253
|
-
| /propose-scenario | **Case A** (thiếu scenario cho AC có sẵn) → báo PO/Dev review trong `feedback/bdd-proposals/`; `/generate-bdd` tự chèn khi `Status: accepted`. **Case B** (requirement mới) → `feedback/prd-change-requests/` — PO phải đưa vào PRD trước, KHÔNG tự vào BDD được; `/validate-traces` nhắc lại kèm số ngày chờ chừng nào `Status: Open` |
|
|
1254
|
-
| /learn | Tiếp tục làm việc — lesson áp dụng ở lệnh kế tiếp |
|
|
1255
|
-
| /sync | `/validate-traces` để xem độ phủ đầy đủ; xử lý mọi `📥 tester feedback` được nêu |
|
|
1256
|
-
| /update-framework | Review `git diff .agent/`, commit; `/sync` để đồng bộ nội dung dự án |
|
|
1257
|
-
|
|
1258
|
-
Định dạng footer như sau:
|
|
1259
|
-
```
|
|
1260
|
-
---
|
|
1261
|
-
Status : {badge}
|
|
1262
|
-
{khối Output Artifacts}
|
|
1263
|
-
Pipeline : Discovery → PRD → [BDD ◀ bạn ở đây] → Tech Design → Code → Dev Self-Check → QC → Trace Audit
|
|
1264
|
-
(lệnh review) Vòng review: [① phân tích ◀] → ② Review Board → ③ --resume
|
|
1265
|
-
Next : {lệnh gợi ý kèm ví dụ tham số}
|
|
1266
|
-
```
|
|
1267
|
-
*(Bỏ dòng `Pipeline` cho các lệnh xuyên suốt liệt kê ở trên.)*
|
|
1268
|
-
|
|
1160
|
+
**Đọc `.agent/steps/report-footer.md`** và áp đúng khuôn footer trong đó (Status Badge ·
|
|
1161
|
+
Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
|
|
1269
1162
|
|
|
1270
1163
|
```
|
|
1271
1164
|
/validate-traces — {domain}
|
|
@@ -1349,6 +1242,20 @@ Trace orphan (tag trỏ vào SC không tồn tại, KHÔNG có row .tsv nào):
|
|
|
1349
1242
|
(Không lệnh nào khác bắt được cái này — row .tsv đã bị xoá bởi version cũ,
|
|
1350
1243
|
hoặc tag ghi sai id ngay từ đầu.)
|
|
1351
1244
|
|
|
1245
|
+
🔴 PRD_UNTRACKED_EDIT — nội dung PRD đổi mà nhãn Version KHÔNG đổi ({n} file):
|
|
1246
|
+
specs/payment/create-invoice/PAY01-create-invoice.md Version 1.3 (không đổi từ lần audit)
|
|
1247
|
+
Bằng chứng : git status — sửa CHƯA commit
|
|
1248
|
+
Mốc cũ : sha a1b2c3d · Version 1.3
|
|
1249
|
+
⚠️ MỌI phán đoán version bên dưới cho PRD này đang dựa vào một nhãn không còn đúng.
|
|
1250
|
+
Không suy đoán được UC nào bị đụng → phải coi cả {n} UC của nó là chưa rõ.
|
|
1251
|
+
Sửa: bump Version + ghi một row changelog NÊU UC bị ảnh hưởng.
|
|
1252
|
+
Đó đúng là việc /amend-prd làm hộ (kèm kiểm va chạm + guard sau-ghi).
|
|
1253
|
+
Không có --accept-edit: dán nhãn lên thay đổi chưa ai xem là đúng cái rào của
|
|
1254
|
+
--realign tồn tại để chặn.
|
|
1255
|
+
|
|
1256
|
+
(hoặc: ⚠️ Chưa kiểm được sửa-ngoài-đường cho {n} PRD ({lý do}) — điểm mù G54 đang MỞ)
|
|
1257
|
+
(hoặc: ⓘ spec_baseline: lần đầu ghi mốc — check có hiệu lực từ lần chạy sau)
|
|
1258
|
+
|
|
1352
1259
|
PRD Version Drift (changelog CÓ nêu UC này — nội dung đổi thật):
|
|
1353
1260
|
{UC}-UC2 — code ở PRD v1.0, PRD giờ ở v1.2 [lệch: tsv, code]
|
|
1354
1261
|
Thay đổi kể từ v1.0:
|
|
@@ -1384,6 +1291,14 @@ Seam & Stub Audit (mồ côi khi ghép luồng):
|
|
|
1384
1291
|
→ /generate-code {owner_uc} lấp logic vào {ClassName#method} tại chỗ, xoá hàm song song, build lại
|
|
1385
1292
|
ⓘ STUB_PENDING — {ClassName#method} ({stub_for}): owner {owner_uc} chưa gen (chưa phải lỗi)
|
|
1386
1293
|
|
|
1294
|
+
{khối dưới CHỈ in khi service_unrouted_count > 0 — else bỏ cả khối}
|
|
1295
|
+
Routing chưa chốt ({service_unrouted_count} scenario) — 🟠 KHÔNG chặn PR:
|
|
1296
|
+
🟠 SERVICE_UNROUTED — {sc_id} ({platform}), domain "{domain}": {reason}
|
|
1297
|
+
→ thêm mapping cho domain "{domain}" vào `services:` của .agent/project-context.yaml,
|
|
1298
|
+
rồi chạy lại /validate-traces — nó tự nâng unrouted → path. KHÔNG cần sinh lại BDD.
|
|
1299
|
+
BDD của các scenario này KHÔNG sai. Đây là bước cấu hình của architect, và nó chỉ CHẶN
|
|
1300
|
+
ở /generate-code (lệnh đó buộc phải biết ghi file vào repo nào).
|
|
1301
|
+
|
|
1387
1302
|
{khối dưới CHỈ in khi Step 7b tìm thấy ≥1 request Status: Open — else bỏ cả khối}
|
|
1388
1303
|
📥 Yêu cầu đổi PRD đang chờ ({n} — chưa ai xử lý):
|
|
1389
1304
|
{UC-ID} — "{title}" chờ {days_waiting} ngày
|