@educa-corp/sdd-framework 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/build.js +113 -19
- package/bin/gate-trace.js +464 -0
- package/bin/index.js +418 -146
- package/bin/lint-trace.js +602 -0
- package/bin/self-check.js +376 -1
- package/bin/trace-schema.json +252 -2
- package/commands/debug.md +123 -511
- package/commands/debug.tmpl +3 -0
- package/commands/define-product.md +86 -510
- package/commands/dev-gen-test.md +86 -510
- package/commands/dev-run-test.md +86 -510
- package/commands/dev-smoke-test.md +86 -510
- package/commands/extend-prd.md +89 -510
- package/commands/extend-prd.tmpl +3 -0
- package/commands/fix-bug.md +118 -509
- package/commands/generate-architecture.md +94 -515
- package/commands/generate-architecture.tmpl +3 -0
- package/commands/generate-bdd.md +85 -509
- package/commands/generate-code.md +86 -510
- package/commands/generate-design-spec.md +86 -510
- package/commands/generate-prd.md +89 -510
- package/commands/generate-prd.tmpl +3 -0
- package/commands/generate-spec-manifest.md +86 -510
- package/commands/generate-tech-docs.md +86 -510
- package/commands/learn.md +172 -496
- package/commands/learn.tmpl +70 -3
- package/commands/map-testids.md +86 -510
- package/commands/propose-scenario.md +86 -510
- package/commands/qc-analyze.md +86 -510
- package/commands/qc-design-test.md +86 -510
- package/commands/qc-plan.md +86 -510
- package/commands/qc-report.md +86 -510
- package/commands/qc-review.md +86 -510
- package/commands/qc-run-test.md +86 -510
- package/commands/refine-prd.md +99 -520
- package/commands/refine-prd.tmpl +3 -0
- package/commands/report-bug.md +86 -510
- package/commands/review-code.md +123 -511
- package/commands/review-code.tmpl +3 -0
- package/commands/review-context.md +93 -514
- package/commands/review-context.tmpl +3 -0
- package/commands/review-tech-docs.md +90 -511
- package/commands/review-tech-docs.tmpl +3 -0
- package/commands/setup-ai-first.md +166 -138
- package/commands/setup-ai-first.tmpl +72 -0
- package/commands/sync.md +50 -106
- package/commands/sync.tmpl +48 -3
- package/commands/update-framework.md +16 -103
- package/commands/update-framework.tmpl +14 -0
- package/commands/validate-traces.md +153 -511
- package/commands/validate-traces.tmpl +67 -1
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/README.md +20 -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 +86 -510
- package/core/commands/dev-smoke-test.md +86 -510
- package/core/commands/extend-prd.md +89 -510
- package/core/commands/fix-bug.md +118 -509
- package/core/commands/generate-architecture.md +94 -515
- package/core/commands/generate-bdd.md +85 -509
- package/core/commands/generate-code.md +86 -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 +86 -510
- 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 +86 -510
- package/core/commands/refine-prd.md +99 -520
- package/core/commands/report-bug.md +86 -510
- package/core/commands/review-code.md +123 -511
- package/core/commands/review-context.md +93 -514
- package/core/commands/review-tech-docs.md +90 -511
- package/core/commands/setup-ai-first.md +166 -138
- package/core/commands/sync.md +50 -106
- package/core/commands/update-framework.md +16 -103
- package/core/commands/validate-traces.md +153 -511
- package/core/hooks/data-guard.js +174 -83
- package/core/hooks/settings.json +2 -1
- package/core/rules/workflow.md +30 -4
- package/core/steps/capture-lesson.md +34 -1
- package/core/steps/context-loader.md +24 -3
- package/core/steps/gate.md +92 -35
- package/core/steps/report-footer.md +23 -0
- package/core/templates/README.md +24 -1
- package/core/templates/ci/trace-gate.yml +146 -0
- package/core/templates/hooks/pre-push +61 -0
- package/docs/02-concepts/architecture.md +25 -6
- package/docs/02-concepts/traceability.md +57 -0
- package/docs/03-guides/architect.md +63 -0
- package/docs/04-reference/commands.md +1 -1
- package/docs/04-reference/model-selection.md +32 -19
- package/docs/explain/21-validate-traces.md +2 -1
- package/docs/explain/27-learn.md +5 -3
- package/hooks/data-guard.js +174 -83
- package/hooks/settings.json +2 -1
- package/package.json +5 -2
- package/rules/workflow.md +30 -4
- package/steps/capture-lesson.md +34 -1
- package/steps/context-loader.md +24 -3
- package/steps/gate.md +92 -35
- package/steps/report-footer.md +23 -0
- package/templates/README.md +24 -1
- package/templates/ci/trace-gate.yml +146 -0
- package/templates/hooks/pre-push +61 -0
- package/scripts/init.sh +0 -49
- package/scripts/upgrade.sh +0 -94
package/core/steps/gate.md
CHANGED
|
@@ -17,35 +17,31 @@ Trước tiên, kiểm tra xem `$ARGUMENTS` có phải là payload JSON từ m
|
|
|
17
17
|
- Đi thẳng tới phần logic riêng của lệnh.
|
|
18
18
|
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).
|
|
19
19
|
|
|
20
|
-
## Bước 0-B —
|
|
20
|
+
## Bước 0-B — Ghi nhận Model *(KHÔNG chặn)*
|
|
21
21
|
|
|
22
|
-
*Bỏ qua
|
|
22
|
+
*Bỏ qua nếu `_agent_mode: true` (sub-agent — orchestrator đã ghi nhận rồi).*
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
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
|
|
25
|
+
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
|
|
26
|
+
model Opus, gắn thêm cảnh báo ngay ở dòng đó.
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
**KHÔNG hỏi người dùng. KHÔNG chờ. KHÔNG dừng.**
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
Y — đúng → tiếp tục
|
|
42
|
-
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)
|
|
43
|
-
──────────────────────────────────────────────────────────────────
|
|
44
|
-
```
|
|
30
|
+
> **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
|
|
31
|
+
> `⚙️ MODEL CHECK` rồi chờ `Y/S/N`. Ba vấn đề cùng chỉ một hướng:
|
|
32
|
+
> **(1)** nó hỏi người dùng thứ mà **agent đã biết chính xác**;
|
|
33
|
+
> **(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
|
|
34
|
+
> gì phát hiện;
|
|
35
|
+
> **(3)** **cả `Y` lẫn `S` đều đi tiếp** — cách duy nhất để nó dừng là tự nguyện gõ `N`.
|
|
36
|
+
> 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
|
|
37
|
+
> 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
|
|
38
|
+
> 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.
|
|
39
|
+
>
|
|
40
|
+
> Khai báo trong report **mạnh hơn** hỏi: đúng nguồn (agent, không phải người), và nằm
|
|
41
|
+
> **cạnh kết quả** để cân nhắc, thay vì nằm trước khi có kết quả để bấm cho xong.
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- "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."
|
|
43
|
+
**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;
|
|
44
|
+
model nhỏ hơn dễ bỏ sót edge case và vi phạm kiến trúc. Đổi: `/model` → chọn Opus.
|
|
49
45
|
|
|
50
46
|
## Bước 1 — Xác định Target File
|
|
51
47
|
|
|
@@ -75,20 +71,81 @@ Lưu toàn bộ context đã nạp vào bộ nhớ để dùng xuyên suốt phi
|
|
|
75
71
|
|
|
76
72
|
## Bước 3 — CHECKPOINT
|
|
77
73
|
|
|
78
|
-
|
|
74
|
+
*Bỏ qua nếu `_agent_mode: true`.*
|
|
75
|
+
|
|
76
|
+
### 3a — Lệnh này có phải chặn không?
|
|
77
|
+
|
|
78
|
+
| Mức | Lệnh nào | `--yes` bỏ qua được? |
|
|
79
|
+
|---|---|:---:|
|
|
80
|
+
| **Không chặn** | Lệnh read-only: `/review-code` · `/validate-traces` · `/debug` · `/review-context` · `/review-tech-docs` | — (vốn không có) |
|
|
81
|
+
| **Chặn thường** | Mọi lệnh sinh/sửa artifact | ✅ |
|
|
82
|
+
| **Chặn CỨNG** | Ghi đè file đã tồn tại · `--resume` áp findings · migrate · prune | ❌ **không bao giờ** |
|
|
83
|
+
|
|
84
|
+
`--yes` trong `$ARGUMENTS` → bỏ qua CHECKPOINT mức *chặn thường*. (Bước 1 đã tách mọi token
|
|
85
|
+
`--` 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
|
|
86
|
+
headless: `claude -p "/generate-code UC1 --yes"`.
|
|
87
|
+
|
|
88
|
+
> **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: …*`
|
|
89
|
+
> 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
|
|
90
|
+
> **nghĩa là gì**.
|
|
91
|
+
> Nguồn máy đọc: `bin/trace-schema.json` → `gate.checkpoint_levels`; `self-check` **R11** fail
|
|
92
|
+
> 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.
|
|
93
|
+
> *(Lệnh không có dòng nào = mức **chặn thường**, mặc định.)*
|
|
94
|
+
|
|
95
|
+
> **Mức *không chặn* là thực thi đúng miễn trừ mà `rules/workflow.md` đã cấp từ trước** —
|
|
96
|
+
> trước G41 file đó viết *"read-only commands may skip CHECKPOINT"* còn gate thì luôn đòi.
|
|
97
|
+
> 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.
|
|
98
|
+
|
|
99
|
+
### 3b — In gì
|
|
100
|
+
|
|
101
|
+
**KHÔNG lặp lại những gì `[CTX LOADED]` vừa in.** Recap của context-loader (Bước 7) đã hiện
|
|
102
|
+
Stack · Platform · Layers · CLAUDE.md · Dict · Entities · Lessons · Service · Status ngay phía
|
|
103
|
+
trên. CHECKPOINT chỉ thêm **một** thông tin mới là `Target`.
|
|
104
|
+
|
|
105
|
+
**Mọi thứ sạch** — recap báo `Status: FULL`, không cờ nào bật → in đúng hai dòng:
|
|
79
106
|
|
|
80
107
|
```
|
|
81
|
-
CHECKPOINT
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
Module : {module nếu có, else "not configured"}
|
|
87
|
-
Domains : {danh sách domain, ngăn cách bởi dấu phẩy}
|
|
108
|
+
CHECKPOINT — Target: {resolved file path}
|
|
109
|
+
Tiếp tục? (Y/N)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**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:
|
|
88
113
|
|
|
114
|
+
```
|
|
115
|
+
CHECKPOINT
|
|
116
|
+
🔴 Service : unresolved — {lý do context-loader đã ghi}
|
|
117
|
+
⚠️ CLAUDE.md: service overlay THIẾU — dùng root (code sinh ra có thể sai stack)
|
|
118
|
+
⚠️ Target : resolve bằng wildcard — {n} file khớp, chọn {file}
|
|
119
|
+
⚠️ Module : not configured — code sinh ra sẽ dùng default
|
|
120
|
+
Status : PARTIAL — thiếu: {danh sách}
|
|
121
|
+
Target : {resolved file path}
|
|
89
122
|
Tiếp tục? (Y/N)
|
|
90
123
|
```
|
|
91
124
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
125
|
+
### 3c — Cờ nào bật, cờ nào KHÔNG
|
|
126
|
+
|
|
127
|
+
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
|
|
128
|
+
đ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:
|
|
129
|
+
|
|
130
|
+
| Bật cờ khi | Nguồn | Mức |
|
|
131
|
+
|---|---|:---:|
|
|
132
|
+
| `active_service = unresolved` | context-loader Bước 2b/2c/Fallback | 🔴 |
|
|
133
|
+
| `Status = MINIMAL` | recap Bước 7 | 🔴 |
|
|
134
|
+
| `Status = PARTIAL` | recap Bước 7 | ⚠️ |
|
|
135
|
+
| CLAUDE.md thiếu, hoặc service overlay thiếu | context-loader Bước 3 | ⚠️ |
|
|
136
|
+
| Target resolve qua wildcard, hoặc nhiều file khớp mà lệnh tự chọn | Bước 1 ở trên | ⚠️ |
|
|
137
|
+
| `module` không cấu hình | recap Bước 7 | ⚠️ |
|
|
138
|
+
|
|
139
|
+
**KHÔNG bật cờ cho:** `Lessons: chưa có` · `Dict: missing` · `Entities: missing`. Đó là
|
|
140
|
+
*"dự án chưa điền"*, không phải *"có gì đó sai"* — chúng ở lại trong recap.
|
|
141
|
+
|
|
142
|
+
> **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**,
|
|
143
|
+
> 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ư
|
|
144
|
+
> 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.
|
|
145
|
+
|
|
146
|
+
### 3d — Chờ trả lời
|
|
147
|
+
|
|
148
|
+
- "Y" → tiếp tục sang các bước riêng của lệnh.
|
|
149
|
+
- "N" → dừng, hỏi người dùng muốn thay đổi gì.
|
|
150
|
+
- Có `--yes` và mức *chặn thường* → coi như "Y", **nhưng vẫn IN khối CHECKPOINT** nếu có cờ
|
|
151
|
+
🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
|
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
Mọi report của lệnh phải kết thúc bằng section footer chuẩn này.
|
|
4
4
|
|
|
5
|
+
## Model *(bắt buộc, một dòng)*
|
|
6
|
+
|
|
7
|
+
In model mà **bạn — agent vừa chạy lệnh này — thực sự đang dùng** (ghi nhận ở Gate Bước 0-B):
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Model: {tên model đang chạy}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Nếu bạn biết mình **không** phải một model Opus, thêm cảnh báo ngay trên cùng dòng:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Model: {tên model} ⚠️ lệnh này khuyến nghị Opus — model nhỏ hơn dễ bỏ sót edge case,
|
|
17
|
+
phân tích spec thiếu sót, vi phạm kiến trúc. Cân nhắc chạy lại
|
|
18
|
+
với /model → Opus trước khi dùng kết quả này.
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
> **Vì sao ở ĐÂY chứ không phải một prompt ở đầu lệnh (GAPS-v3 G41):** trước đây Gate hiện
|
|
22
|
+
> `⚙️ MODEL CHECK` rồi chờ `Y/S/N`. Nó **hỏi người dùng thứ agent đã biết**, câu trả lời
|
|
23
|
+
> **không kiểm chứng được**, và **cả `Y` lẫn `S` đều đi tiếp** — tức không chặn được ai, mà
|
|
24
|
+
> tốn một lần chặn ở mọi lệnh (20 lệnh cho một feature). Khai báo ở footer đúng nguồn hơn
|
|
25
|
+
> (agent tự khai, không phải người tự khai) và đúng chỗ hơn: nó nằm **cạnh kết quả** để
|
|
26
|
+
> người đọc cân nhắc có nên tin, thay vì nằm trước khi có kết quả để bấm cho xong.
|
|
27
|
+
|
|
5
28
|
## Status Badge
|
|
6
29
|
|
|
7
30
|
Chọn một theo kết quả:
|
package/core/templates/README.md
CHANGED
|
@@ -17,7 +17,28 @@ commands/generate-bdd.md
|
|
|
17
17
|
|
|
18
18
|
Không lệnh nào đọc một path template lúc chạy. `paths.feature_template` / `paths.prd_template` từng tồn tại trong `project-context.yaml` nhưng chưa bao giờ có tác dụng — đã được gỡ bỏ (xem `GAPS.md` G9).
|
|
19
19
|
|
|
20
|
-
**Thêm nữa:** `.agent/` là vùng bị ghi đè. `/update-framework` chạy `npx … --init`, và `--init` copy `core/` → `.agent/` **vô điều kiện** (`bin/index.js` → `
|
|
20
|
+
**Thêm nữa:** `.agent/` là vùng bị ghi đè. `/update-framework` chạy `npx … --init`, và `--init` copy `core/` → `.agent/` **vô điều kiện** (`bin/index.js` → `installCore`). File duy nhất được giữ lại là `.agent/project-context.yaml`. Nên mọi chỉnh sửa ở `.agent/templates/` sẽ **biến mất** ở lần nâng cấp kế tiếp — từ v0.4.2 thì không còn im lặng: bản cũ được lưu vào `.agent/.overwritten-{version}-{date}/` và được liệt kê ra (`GAPS.md` G24). Nhưng vẫn phải áp lại bằng tay mỗi version, nên đây không phải chỗ để đặt thay đổi.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Ngoại lệ: `ci/` và `hooks/` — template để COPY RA, không phải để build
|
|
25
|
+
|
|
26
|
+
Hai thư mục này **không** giống phần còn lại của `templates/`. Chúng không được `{{include}}` vào lệnh nào, và **không** được đọc lúc chạy. Chúng là file **hoàn chỉnh, dùng ngay**, chờ một người copy ra khỏi `.agent/`:
|
|
27
|
+
|
|
28
|
+
| File | Copy tới | Làm gì |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `ci/trace-gate.yml` | `.github/workflows/` của project | Chặn PR khi trace có cờ 🔴 (`--gate-trace`) |
|
|
31
|
+
| `hooks/pre-push` | `.git/hooks/pre-push` (rồi `chmod +x`) | Chặn push khi sổ trace hỏng cấu trúc (`--lint-trace`) |
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# từ gốc project
|
|
35
|
+
mkdir -p .github/workflows && cp .agent/templates/ci/trace-gate.yml .github/workflows/
|
|
36
|
+
cp .agent/templates/hooks/pre-push .git/hooks/pre-push && chmod +x .git/hooks/pre-push
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Phải copy RA, không dùng tại chỗ** — vì đúng cái lý do cả file README này nói: `.agent/` bị ghi đè mỗi lần nâng cấp, và `.git/hooks/` thì git không bao giờ chạy từ chỗ khác. Copy ra rồi thì chúng là file của project: sửa tuỳ ý, nâng cấp framework không đụng tới.
|
|
40
|
+
|
|
41
|
+
Vì sao chúng tồn tại → `GAPS-v3.md` G39: framework phát hiện được một lớp lỗi mà build xanh + test xanh không thấy, nhưng trước đó việc phát hiện phụ thuộc vào có người tự nguyện chạy một lệnh chat. Hai file này là chỗ nó chặn bằng máy.
|
|
21
42
|
|
|
22
43
|
## Muốn đổi cấu trúc artifact sinh ra thì làm gì
|
|
23
44
|
|
|
@@ -43,5 +64,7 @@ Rồi phát hành version mới; project chạy `/update-framework` để nhận
|
|
|
43
64
|
| `product-definition.template.md` | `commands/define-product.tmpl` | product definition |
|
|
44
65
|
| `platform-guide.template.md` | (tham khảo) | — |
|
|
45
66
|
| `project-context.yaml` | **không** include — được copy thẳng làm file config khởi tạo | `.agent/project-context.yaml` |
|
|
67
|
+
| `ci/trace-gate.yml` | **không** include — người dùng copy ra | `.github/workflows/trace-gate.yml` |
|
|
68
|
+
| `hooks/pre-push` | **không** include — người dùng copy ra | `.git/hooks/pre-push` |
|
|
46
69
|
|
|
47
70
|
> Lưu ý `project-context.yaml` là ngoại lệ duy nhất: nó **được** copy ra làm file thật của project, và **được bảo vệ** khỏi ghi đè khi nâng cấp (chỉ tạo nếu chưa tồn tại).
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
# SDD Framework — Trace Gate (GitHub Actions)
|
|
3
|
+
#
|
|
4
|
+
# COPY file này vào .github/workflows/ của project. Nó KHÔNG tự chạy từ
|
|
5
|
+
# .agent/templates/ — mọi thứ trong .agent/ là bản sinh ra, bị ghi đè mỗi lần
|
|
6
|
+
# /update-framework.
|
|
7
|
+
#
|
|
8
|
+
# VÌ SAO CẦN (GAPS-v3 G39): framework phát hiện được một lớp lỗi mà build xanh +
|
|
9
|
+
# test từng-UC xanh KHÔNG thấy — luồng ghép chạy vào hàm rỗng (SEAM_UNWIRED,
|
|
10
|
+
# STUB_UNRESOLVED), hoặc code trỏ vào scenario đã bị xoá (ORPHANED, TRACE_ORPHAN).
|
|
11
|
+
# Nhưng trước G39 việc phát hiện đó phụ thuộc vào có người TỰ NGUYỆN chạy
|
|
12
|
+
# /validate-traces trong Claude Code rồi đọc report bằng mắt. Cái gì không chặn
|
|
13
|
+
# thì sau sprint thứ ba không ai làm. Đây là chỗ nó chặn.
|
|
14
|
+
#
|
|
15
|
+
# GIỚI HẠN — đọc trước khi tin:
|
|
16
|
+
# Job này chứng minh "report khớp SỔ, và sổ không có cờ 🔴".
|
|
17
|
+
# Nó KHÔNG chứng minh "sổ khớp CODE" — việc đó cần quét tag trong source, đọc
|
|
18
|
+
# .feature, so version, tức cần /validate-traces (một lệnh LLM, không chạy được
|
|
19
|
+
# trong CI thường). Nên nó bắt ca phổ biến "quên chạy lại /validate-traces",
|
|
20
|
+
# nhưng KHÔNG bắt ca "sửa code mà không đụng sổ".
|
|
21
|
+
# Muốn bịt nốt: xem job `require-fresh-audit` ở cuối file.
|
|
22
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
name: Trace Gate
|
|
25
|
+
|
|
26
|
+
on:
|
|
27
|
+
pull_request:
|
|
28
|
+
push:
|
|
29
|
+
branches: [main, master, develop]
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
trace-gate:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
with:
|
|
37
|
+
# Cần lịch sử để job require-fresh-audit so được diff. Bỏ nếu không dùng job đó.
|
|
38
|
+
fetch-depth: 0
|
|
39
|
+
# Spec/trace nằm trong submodule (umbrella + spec_source)? Bỏ comment:
|
|
40
|
+
# submodules: recursive
|
|
41
|
+
|
|
42
|
+
- uses: actions/setup-node@v4
|
|
43
|
+
with:
|
|
44
|
+
node-version: '20'
|
|
45
|
+
|
|
46
|
+
# ── 1. Cấu trúc sổ ───────────────────────────────────────────────────────
|
|
47
|
+
# Sổ trace 24 cột do LLM ghi bằng tay. Một dấu tab thiếu dồn mọi ô sang trái
|
|
48
|
+
# và ô `status` nhận một ngày tháng — trước G38 không gì báo. Bước này chặn.
|
|
49
|
+
# Cũng bắt marker conflict git lọt vào sổ (T7) và sổ thiếu luật merge (T10).
|
|
50
|
+
- name: Lint sổ trace
|
|
51
|
+
run: npx -y @educa-corp/sdd-framework@latest --lint-trace
|
|
52
|
+
|
|
53
|
+
# ── 2. Cổng chặn PR ──────────────────────────────────────────────────────
|
|
54
|
+
# --gate-trace tự chạy lại lint ở tầng G1, nên bước 1 ở trên là để có log
|
|
55
|
+
# riêng dễ đọc khi đỏ. Muốn gọn thì bỏ bước 1 và chỉ giữ bước này.
|
|
56
|
+
- name: Trace gate (cờ 🔴 chặn PR)
|
|
57
|
+
run: npx -y @educa-corp/sdd-framework@latest --gate-trace
|
|
58
|
+
|
|
59
|
+
# ── 3. (tuỳ chọn) Đưa kết quả vào PR summary ─────────────────────────────
|
|
60
|
+
- name: Ghi kết quả vào job summary
|
|
61
|
+
if: always()
|
|
62
|
+
run: |
|
|
63
|
+
npx -y @educa-corp/sdd-framework@latest --gate-trace --json --warn-only \
|
|
64
|
+
> gate.json || true
|
|
65
|
+
{
|
|
66
|
+
echo '## Trace Gate'
|
|
67
|
+
echo '```json'
|
|
68
|
+
cat gate.json
|
|
69
|
+
echo '```'
|
|
70
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
71
|
+
|
|
72
|
+
# ───────────────────────────────────────────────────────────────────────────
|
|
73
|
+
# Ép audit phải TƯƠI khi thứ report đang KHẲNG ĐỊNH bị đổi.
|
|
74
|
+
#
|
|
75
|
+
# Bịt cái lỗ mà trace-gate không bịt được: gate chứng minh "report khớp SỔ",
|
|
76
|
+
# không chứng minh "sổ khớp CODE" — việc đó cần /validate-traces, một lệnh LLM
|
|
77
|
+
# không chạy được ở đây. Nên job này dùng một PROXY: không verify được thì ĐÒI
|
|
78
|
+
# BẰNG CHỨNG có người vừa verify.
|
|
79
|
+
#
|
|
80
|
+
# ĐO BẰNG TAG, KHÔNG BẰNG `src/**`:
|
|
81
|
+
# Framework có luật boundary-only tagging — chỉ Controller/Handler/Middleware/
|
|
82
|
+
# Steps mang tag @trace; Entity/Repository/DTO/Interface/Base KHÔNG. Nên câu
|
|
83
|
+
# hỏi "PR có sửa src/ không?" chặn cả PR chỉ thêm một field vào DTO — một file
|
|
84
|
+
# không mang lời khẳng định trace nào. Cái gì báo oan thì bị tắt, rồi mất luôn
|
|
85
|
+
# phần thật sự cần chặn.
|
|
86
|
+
# Câu hỏi đúng: "PR có chạm dòng nào mang tag mà report đang khẳng định không?"
|
|
87
|
+
#
|
|
88
|
+
# sửa log trong Controller → cho qua (bản `src/**` cũ: chặn oan)
|
|
89
|
+
# thêm field vào DTO → cho qua (bản cũ: chặn oan)
|
|
90
|
+
# thêm method + @implements → CHẶN
|
|
91
|
+
# lấp một @trace.stub → CHẶN
|
|
92
|
+
#
|
|
93
|
+
# KHÔNG cần sửa gì theo layout project — tag là tag, ở đâu cũng vậy.
|
|
94
|
+
#
|
|
95
|
+
# BẢY TAG dưới đây là NGUỒN của đúng 4 cờ chặn PR. Chúng được khai trong
|
|
96
|
+
# bin/trace-schema.json → gate.audit_invalidating_tags, và self-check R10 fail
|
|
97
|
+
# build nếu file này không nhắc đủ — tag đổi tên mà đây không biết thì grep
|
|
98
|
+
# không khớp gì, job LUÔN XANH, và cổng mù trong im lặng.
|
|
99
|
+
#
|
|
100
|
+
# GIỚI HẠN ĐÃ BIẾT: đổi tên class (AuthService → AuthenticationService) không
|
|
101
|
+
# chạm dòng tag ⇒ job này bỏ lọt, dù cột implemented_by giờ trỏ vào tên không
|
|
102
|
+
# còn. Chấp nhận có chủ ý: ca đó ít gặp và KHÔNG im lặng (/validate-traces lần
|
|
103
|
+
# sau báo ngay), còn báo oan thì xảy ra mỗi ngày.
|
|
104
|
+
# Muốn chặt hơn (bắt cả rename, giá là chặn cả việc sửa log trong Controller):
|
|
105
|
+
# đổi bước dưới thành — lấy danh sách file đã đổi, rồi `grep -l` bảy tag đó
|
|
106
|
+
# TRÊN NỘI DUNG FILE thay vì trên diff.
|
|
107
|
+
# ───────────────────────────────────────────────────────────────────────────
|
|
108
|
+
require-fresh-audit:
|
|
109
|
+
if: github.event_name == 'pull_request'
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
steps:
|
|
112
|
+
- uses: actions/checkout@v4
|
|
113
|
+
with: { fetch-depth: 0 }
|
|
114
|
+
|
|
115
|
+
- name: Đổi thứ report khẳng định thì audit phải đổi theo
|
|
116
|
+
shell: bash
|
|
117
|
+
run: |
|
|
118
|
+
BASE="origin/${{ github.base_ref }}"
|
|
119
|
+
|
|
120
|
+
# 7 tag sinh ra 4 cờ chặn PR — khai ở bin/trace-schema.json,
|
|
121
|
+
# gate.audit_invalidating_tags (self-check R10 canh danh sách này khớp).
|
|
122
|
+
TAGS='@trace\.(implements|verifies|seam_port|seam_pending|stub|stub_owner|stub_for)'
|
|
123
|
+
|
|
124
|
+
# Chạm dòng mang tag = report có thể đã hết đúng. -U0 để chỉ lấy dòng thật đổi.
|
|
125
|
+
touched=$(git diff -U0 "$BASE"...HEAD | grep -E "^[+-].*${TAGS}" | head -5 || true)
|
|
126
|
+
audit=$(git diff --name-only "$BASE"...HEAD | grep -E 'trace-report\.json$' | head -1 || true)
|
|
127
|
+
|
|
128
|
+
if [ -n "$touched" ] && [ -z "$audit" ]; then
|
|
129
|
+
echo "::error::PR đổi tag trace nhưng không kèm trace-report.json được sinh lại."
|
|
130
|
+
echo ""
|
|
131
|
+
echo "Những dòng này đã đổi:"
|
|
132
|
+
echo "$touched" | sed 's/^/ /'
|
|
133
|
+
echo ""
|
|
134
|
+
echo "Trace gate chỉ chứng minh 'report khớp SỔ'. Tag vừa đổi mà chưa audit lại"
|
|
135
|
+
echo "thì mọi cờ 🔴 trong report nói về trạng thái TRƯỚC khi bạn sửa."
|
|
136
|
+
echo ""
|
|
137
|
+
echo "Chạy trong Claude Code: /validate-traces"
|
|
138
|
+
echo "Rồi commit: {trace_dir}/trace-report.json + *.tsv"
|
|
139
|
+
exit 1
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
if [ -n "$touched" ]; then
|
|
143
|
+
echo "✅ Tag trace có đổi, và audit đã được sinh lại cùng PR."
|
|
144
|
+
else
|
|
145
|
+
echo "✅ PR không chạm tag nào mà report đang khẳng định — audit vẫn còn đúng."
|
|
146
|
+
fi
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
# SDD Framework — git pre-push hook
|
|
4
|
+
#
|
|
5
|
+
# CÀI (từ gốc project):
|
|
6
|
+
# cp .agent/templates/hooks/pre-push .git/hooks/pre-push
|
|
7
|
+
# chmod +x .git/hooks/pre-push
|
|
8
|
+
#
|
|
9
|
+
# Trên Windows: Git for Windows chạy hook bằng sh nên file này dùng được như vậy.
|
|
10
|
+
#
|
|
11
|
+
# VÌ SAO CÓ HOOK NÀY khi đã có CI (GAPS-v3 G39/G40): nó chặn ở chỗ RẺ NHẤT.
|
|
12
|
+
# Cụ thể là T7 — marker conflict git (`<<<<<<< HEAD`) lọt vào sổ trace. Một khi
|
|
13
|
+
# thứ đó vào nhánh chung thì mọi người kéo về đều có sổ hỏng, và sổ trace là dữ
|
|
14
|
+
# liệu KHÔNG dựng lại được. Bắt trước lúc push tốn 2 giây; bắt ở CI thì đã muộn
|
|
15
|
+
# một vòng, bắt bằng mắt thì thường là ba tuần sau.
|
|
16
|
+
#
|
|
17
|
+
# CỐ Ý CHỈ LINT, KHÔNG GATE:
|
|
18
|
+
# --lint-trace = cấu trúc sổ. Nhanh, offline được sau lần đầu, và một lỗi ở đây
|
|
19
|
+
# LUÔN là lỗi thật (tab lệch, marker conflict, enum sai).
|
|
20
|
+
# --gate-trace = cờ 🔴. Cần trace-report.json còn tươi, mà giữa lúc làm việc thì
|
|
21
|
+
# nó thường chưa tươi — đỏ liên tục ⇒ người ta gõ --no-verify ⇒
|
|
22
|
+
# mất luôn cả phần lint. Cờ 🔴 để CI chặn.
|
|
23
|
+
#
|
|
24
|
+
# Bỏ qua một lần (dùng có ý thức, đừng thành phản xạ): git push --no-verify
|
|
25
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
# Không có node thì im lặng cho qua — hook không được làm người ta không push được
|
|
28
|
+
# vì lý do không liên quan tới việc họ đang làm.
|
|
29
|
+
command -v node >/dev/null 2>&1 || exit 0
|
|
30
|
+
|
|
31
|
+
# Không có sổ trace thì không có gì để kiểm (project chưa chạy /generate-bdd lần nào).
|
|
32
|
+
# Sửa đường dẫn nếu trace_dir của project khác (vd ../.trace, hay {spec_source}/.trace).
|
|
33
|
+
TRACE_DIR=".trace"
|
|
34
|
+
[ -d "$TRACE_DIR" ] || exit 0
|
|
35
|
+
|
|
36
|
+
echo "→ Lint sổ trace trước khi push ..."
|
|
37
|
+
|
|
38
|
+
if npx -y @educa-corp/sdd-framework@latest --lint-trace --trace "$TRACE_DIR"; then
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
cat <<'MSG'
|
|
43
|
+
|
|
44
|
+
──────────────────────────────────────────────────────────────────────
|
|
45
|
+
🔴 PUSH BỊ CHẶN — sổ trace hỏng cấu trúc.
|
|
46
|
+
|
|
47
|
+
Sổ trace là dữ liệu KHÔNG regenerate được. Đẩy một sổ hỏng lên nhánh
|
|
48
|
+
chung thì mọi người kéo về đều nhận bản hỏng.
|
|
49
|
+
|
|
50
|
+
Thường gặp nhất — marker conflict git chưa giải (T7):
|
|
51
|
+
1. Mở file lint vừa nêu, xoá 3 dòng <<<<<<< ======= >>>>>>>
|
|
52
|
+
2. GIỮ CẢ HAI BÊN, đừng chọn một bên (mất row là mất vĩnh viễn)
|
|
53
|
+
3. npx @educa-corp/sdd-framework --lint-trace # xác nhận sạch
|
|
54
|
+
4. /validate-traces trong Claude Code # reconcile row trùng
|
|
55
|
+
|
|
56
|
+
Playbook đầy đủ: docs/02-concepts/traceability.md
|
|
57
|
+
Bỏ qua một lần: git push --no-verify
|
|
58
|
+
──────────────────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
MSG
|
|
61
|
+
exit 1
|
|
@@ -61,15 +61,34 @@ Spec-driven thành/bại phụ thuộc **~80%** vào việc context được n
|
|
|
61
61
|
## Template Pipeline
|
|
62
62
|
|
|
63
63
|
```
|
|
64
|
-
.tmpl
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
▼ ▼
|
|
68
|
-
bin/self-check.js (fail build) .agent/commands/*.md (runtime)
|
|
64
|
+
.tmpl + steps/*.md ──build──► commands/*.md ──► core/* ──► .agent/ 904 KB
|
|
65
|
+
│ ▲
|
|
66
|
+
bin/self-check.js (fail build) --init cài vào đây
|
|
69
67
|
```
|
|
70
68
|
|
|
71
|
-
|
|
69
|
+
**Vì sao slim (G45):** build inline `{{include:}}` vào **từng** file lệnh. Với 32 lệnh, kết quả là
|
|
70
|
+
2069 KB mà chỉ 580 KB là nội dung riêng của chúng — **72% là vài step giống hệt nhau, chép 30 lần**.
|
|
71
|
+
`/generate-code` từng nặng 108 KB (≈27k token đọc **trước** khi làm gì), gần một nửa không nói gì về
|
|
72
|
+
việc sinh code. Cái giá thật không phải tiền: trên PRD nhiều UC nó làm tăng rủi ro **cạn context
|
|
73
|
+
giữa lúc ghi sổ trace**.
|
|
74
|
+
|
|
75
|
+
| Step | Xử lý trong `core/` | Vì sao |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `context-loader.md` (33 K × 29) | **đọc lúc chạy** | 64% lãng phí. Bỏ sót ⇒ lệnh **dừng ngay** vì thiếu path/config — hỏng ồn ào |
|
|
78
|
+
| `report-footer.md` (7 K × 32) | **đọc lúc chạy** | 16%. Bỏ sót ⇒ report kém cấu trúc, không hỏng gì |
|
|
79
|
+
| `gate.md` (7 K × 30) | **giữ inline** | Chỉ 15%, nhưng là **lưới an toàn** (model check · resolve target · CHECKPOINT). Bỏ sót ⇒ lệnh **vẫn chạy** mà không còn cổng nào — hỏng **âm thầm** |
|
|
80
|
+
|
|
81
|
+
Kết quả: `/generate-code` 108 KB → **69 KB**, `/refine-prd` 85 KB → **45 KB**.
|
|
82
|
+
|
|
83
|
+
> **Một biến thể duy nhất.** Bản đầu của G45 phải build **hai** bản: `commands/*.md` inline đầy đủ
|
|
84
|
+
> cho legacy mode (`--project` / không cờ) — vì nó copy thẳng file đó vào `.claude/commands/` mà
|
|
85
|
+
> **không** cài `.agent/`, nên không có `.agent/steps/` để đọc — và bản slim cho `--init`.
|
|
86
|
+
> **G50 gỡ hẳn legacy mode**, nên giờ mọi bản cài đều có `.agent/steps/` và nhánh build thứ hai
|
|
87
|
+
> biến mất. Hai nhánh build gần giống nhau là nợ chờ lệch.
|
|
88
|
+
|
|
89
|
+
- Cơ chế `{{include:steps/...}}` → single source of truth ở `.tmpl` + `steps/`.
|
|
72
90
|
- **Không sửa tay** `commands/*.md` / `.agent/` — sửa `.tmpl`/`steps` rồi `node bin/build.js`. *(Quy ước + memory bảo vệ, không phải hook.)*
|
|
91
|
+
- **Sửa `steps/context-loader.md` hay `report-footer.md` giờ có hiệu lực NGAY** ở project đã cài — chúng được đọc lúc chạy, không còn phải build + publish + `/update-framework`.
|
|
73
92
|
- **Template artifact cũng bị inline lúc build.** `templates/feature.template` và `prd.template.md` được `{{include}}` **nướng cứng** vào file lệnh, nên lệnh không đọc path template lúc chạy — sửa `.agent/templates/` **không có tác dụng**. Đổi cấu trúc `.feature`/PRD = sửa `templates/*` trong repo framework rồi build lại.
|
|
74
93
|
|
|
75
94
|
### Self-check — contract trace không được lệch
|
|
@@ -119,6 +119,63 @@ flowchart LR
|
|
|
119
119
|
|
|
120
120
|
---
|
|
121
121
|
|
|
122
|
+
## Sổ trace trong git — và khi nó conflict
|
|
123
|
+
|
|
124
|
+
Sổ trace là **dữ liệu không dựng lại được**, nằm trong git, và **được nhiều người ghi trên
|
|
125
|
+
nhiều nhánh song song**. Ba thứ đó cộng lại nghĩa là git phải được dạy cách merge nó.
|
|
126
|
+
|
|
127
|
+
### Luật đã cài sẵn
|
|
128
|
+
|
|
129
|
+
`/setup-ai-first` tạo `{trace_dir}/.gitattributes`; `/sync` Step 4c kiểm và tạo hộ nếu thiếu:
|
|
130
|
+
|
|
131
|
+
```gitattributes
|
|
132
|
+
*.tsv text eol=lf merge=union
|
|
133
|
+
*.jsonl text eol=lf merge=union
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
| Luật | Không có nó thì sao |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `merge=union` | Hai nhánh cùng ghi một sổ → **conflict**. Giải bằng "take mine" = **mất row của người kia, im lặng**. Với `trace-history.jsonl` (append cuối file) thì **mọi** cặp nhánh song song đều conflict. |
|
|
139
|
+
| `text eol=lf` | Một máy ghi CRLF → git thấy **mọi dòng** đã đổi → union giữ cả hai bản → **nhân đôi cả file**, gồm cả dòng header. Team mixed Windows/macOS gặp ca này mà không ai làm gì sai. |
|
|
140
|
+
|
|
141
|
+
`union` là driver **built-in** của git — không ai cần chạy `git config` gì thêm.
|
|
142
|
+
|
|
143
|
+
> **`*.json` cố ý KHÔNG có trong danh sách.** `trace-report.json` nằm cùng thư mục và union
|
|
144
|
+
> trên JSON tạo ra **JSON không hợp lệ** → panel VS Code parse lỗi. Nó **sinh lại được**:
|
|
145
|
+
> conflict ở đó thì chạy lại `/validate-traces`, đừng merge tay.
|
|
146
|
+
|
|
147
|
+
### Đánh đổi có chủ ý: trùng row thay vì mất row
|
|
148
|
+
|
|
149
|
+
`merge=union` **có thể** tạo hai row cùng `sc_id`. Đó là **thiết kế**, không phải lỗi:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
trùng row → --lint-trace T4 bắt được → /validate-traces reconcile → sạch
|
|
153
|
+
mất row → KHÔNG có gì bắt được → phát hiện sau 3 tuần → khôi phục bằng tay
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Đây là lý do luật merge và `--lint-trace` là **một cặp**: union chuyển lỗi từ dạng *im lặng*
|
|
157
|
+
sang dạng *bắt được*, và cái bắt nó phải tồn tại. Có union mà không có lint thì chỉ là đổi chỗ lỗi.
|
|
158
|
+
|
|
159
|
+
### Playbook — 4 bước
|
|
160
|
+
|
|
161
|
+
Vẫn thấy conflict trong `{trace_dir}/` (nhánh phân kỳ quá xa, hoặc luật vừa mới được thêm):
|
|
162
|
+
|
|
163
|
+
1. **GIỮ CẢ HAI BÊN.** Xoá ba dòng marker (`<<<<<<<`, `=======`, `>>>>>>>`), giữ toàn bộ row
|
|
164
|
+
của cả hai phía. **Đừng chọn một bên.**
|
|
165
|
+
2. `npx @educa-corp/sdd-framework --lint-trace` — T7 xác nhận không còn marker, T4 chỉ ra row nào trùng.
|
|
166
|
+
3. `/validate-traces` — reconcile row trùng về một row đúng, tính lại `status`.
|
|
167
|
+
4. Commit.
|
|
168
|
+
|
|
169
|
+
**Ba điều không bao giờ làm:**
|
|
170
|
+
|
|
171
|
+
| ❌ | Vì sao |
|
|
172
|
+
|---|---|
|
|
173
|
+
| `git checkout --ours/--theirs` trên file trace | Xoá sạch row của một phía. Không có gì báo. |
|
|
174
|
+
| Xoá file trace để "cho sạch" rồi chạy lại pipeline | Sổ **không regenerate được** — `trace-history.jsonl` mất là mất vĩnh viễn. |
|
|
175
|
+
| Commit khi còn marker | Marker thành một "row" TSV. `--lint-trace` T7 bắt, nhưng nếu chưa cắm vào CI thì nó vào nhánh chung. |
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
122
179
|
## Đọc tiếp (Next)
|
|
123
180
|
|
|
124
181
|
- [Architecture](architecture.md) — 3 lớp & context-loader
|
|
@@ -91,6 +91,69 @@ flowchart LR
|
|
|
91
91
|
|
|
92
92
|
---
|
|
93
93
|
|
|
94
|
+
## Cắm vào CI — cái gì chặn được bằng máy
|
|
95
|
+
|
|
96
|
+
Đây là việc của SA/Lead, không phải của dev từng người: **kỷ luật nào không chặn thì sau
|
|
97
|
+
sprint thứ ba không ai làm.** Framework có hai lệnh CLI trả exit code — cắm được vào pipeline:
|
|
98
|
+
|
|
99
|
+
| Lệnh | Chặn gì | Đặt ở đâu |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `--lint-trace` | **Cấu trúc sổ**: header lệch · row sai số ô · enum sai · `sc_id` trùng · marker conflict git · `.jsonl` hỏng. Cộng hai điều kiện **cấu hình** ở mức ⚠️: thiếu luật merge · sổ bị gitignore | pre-push **và** CI |
|
|
102
|
+
| `--gate-trace` | **Cấu hình** (nâng hai ⚠️ trên thành chặn) + **cờ 🔴**: `ORPHANED` · `TRACE_ORPHAN` · `SEAM_UNWIRED` · `STUB_UNRESOLVED` | CI (cần report tươi) |
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx @educa-corp/sdd-framework --lint-trace # exit 1 nếu sổ hỏng
|
|
106
|
+
npx @educa-corp/sdd-framework --gate-trace # exit 1 nếu có cờ 🔴
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Mẫu sẵn dùng: `.agent/templates/ci/trace-gate.yml` (GitHub Actions) · `.agent/templates/hooks/pre-push`.
|
|
110
|
+
**Copy ra khỏi `.agent/`** trước khi dùng — mọi thứ trong đó bị ghi đè mỗi lần `/update-framework`.
|
|
111
|
+
|
|
112
|
+
### Bốn tầng của `--gate-trace`, và vì sao thứ tự đó
|
|
113
|
+
|
|
114
|
+
0. **Sổ được bảo vệ?** — sổ có **nằm trong git**? git có **biết cách gộp** sổ? Kiểm cấu trúc của một quyển sổ sắp mất thì vô nghĩa. Hai điều kiện này `lint-trace` đã phát hiện dưới dạng ⚠️; gate **nâng** chúng thành lỗi chặn — *pre-push nhắc, CI chặn*.
|
|
115
|
+
1. **Sổ đúng hình dạng?** (gọi `--lint-trace`) — phán trạng thái trên sổ lệch cột là phán trên dữ liệu rác.
|
|
116
|
+
2. **Report còn tươi?** — đối chiếu `trace-report.json` với chính sổ TSV nó khai là đang mô tả.
|
|
117
|
+
Không có tầng này thì cổng là **sân khấu**: chạy `/validate-traces` một lần, commit report,
|
|
118
|
+
rồi sửa gì cũng được — CI đọc report cũ và cho qua mãi.
|
|
119
|
+
3. **Có cờ 🔴?** — đếm counter, nêu tên thủ phạm kèm câu `fix` của chính framework.
|
|
120
|
+
|
|
121
|
+
### Giới hạn — nói rõ với team, đừng để họ tin quá
|
|
122
|
+
|
|
123
|
+
> `--gate-trace` chứng minh **"report khớp SỔ"**.
|
|
124
|
+
> Chỉ `/validate-traces` chứng minh được **"sổ khớp CODE"** (nó phải quét tag trong source,
|
|
125
|
+
> đọc `.feature`, so version — việc của LLM).
|
|
126
|
+
|
|
127
|
+
Nên cổng bắt được ca phổ biến *"quên chạy lại `/validate-traces`"*, nhưng **không** bắt được
|
|
128
|
+
*"sửa code mà không đụng sổ"*. Cổng in ra đúng giới hạn này mỗi lần chạy, kể cả khi xanh.
|
|
129
|
+
|
|
130
|
+
Đường bịt: job **`require-fresh-audit`** trong template — **bật mặc định**. Nó hỏi
|
|
131
|
+
*"PR có chạm dòng nào mang một trong 7 tag mà report đang khẳng định không?"*
|
|
132
|
+
(`@trace.implements` · `verifies` · `seam_port` · `seam_pending` · `stub` · `stub_owner` ·
|
|
133
|
+
`stub_for` — nguồn của đúng 4 cờ 🔴). Có mà không kèm `trace-report.json` mới → **chặn**.
|
|
134
|
+
|
|
135
|
+
| PR làm gì | Kết quả |
|
|
136
|
+
|---|:---:|
|
|
137
|
+
| Sửa log trong Controller · thêm field vào DTO · đổi query Repository | ✅ cho qua |
|
|
138
|
+
| Thêm/xoá method mang `@trace.implements` · lấp một `@trace.stub` | 🔴 chặn |
|
|
139
|
+
|
|
140
|
+
> **Không dùng `^src/`** — framework có luật *boundary-only tagging*: Entity/Repository/DTO/
|
|
141
|
+
> Interface **không** mang tag, nên `^src/` chặn cả PR chỉ thêm một field vào DTO. Báo oan ⇒
|
|
142
|
+
> cổng bị tắt ⇒ mất luôn phần thật sự cần chặn. `self-check` **R10** fail build nếu file CI
|
|
143
|
+
> thiếu một tag — thiếu thì `grep` không khớp gì và job **luôn xanh**.
|
|
144
|
+
>
|
|
145
|
+
> **Giới hạn:** đổi tên class không chạm dòng tag ⇒ bỏ lọt. Ca đó ít gặp và **không im lặng**
|
|
146
|
+
> (`/validate-traces` lần sau báo ngay). Biến thể chặt hơn ghi trong comment của template.
|
|
147
|
+
|
|
148
|
+
### Cờ 🟠 cố ý KHÔNG chặn
|
|
149
|
+
|
|
150
|
+
`PRD_DRIFT` · `BDD_DRIFT` · `TECHDOC_DRIFT` · `DESIGNSPEC_DRIFT` là **nợ** — "code chưa theo
|
|
151
|
+
kịp spec" — không phải code hỏng. Chặn PR vì nợ làm cổng đỏ liên tục, và cổng đỏ liên tục sẽ
|
|
152
|
+
bị tắt, mất luôn cả phần 🔴. `bin/self-check.js` **R9** fail build nếu ai nhét một cờ 🟠 vào
|
|
153
|
+
danh sách chặn.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
94
157
|
## Lệnh của bạn (Your commands)
|
|
95
158
|
|
|
96
159
|
`/generate-architecture` · `/generate-tech-docs` · `/review-tech-docs` · `/refine-prd` (SA lens) · `/review-code` · `/generate-spec-manifest`
|
|
@@ -101,7 +101,7 @@ Mọi lệnh chạy chung một **Gate** (model check → target → context-loa
|
|
|
101
101
|
|------|-------|--------|-------|
|
|
102
102
|
| `/report-bug` | Lỗi phát hiện | `feedback/bug-reports/` (spec-anchored) | Tester/QC |
|
|
103
103
|
| `/propose-scenario` | Scenario thiếu | **A:** `feedback/bdd-proposals/` → `/generate-bdd` chèn · **B:** `feedback/prd-change-requests/` → PO chạy `/extend-prd` | Tester/QC |
|
|
104
|
-
| `/learn` | Định hướng lặp lại | `project-lessons.md` | Tất cả |
|
|
104
|
+
| `/learn` · `/learn --review` | Định hướng lặp lại · rà/retire lesson cũ | `project-lessons.md` | Tất cả |
|
|
105
105
|
| `/sync` | (umbrella) | Pull + submodule + nổi feedback + Living Docs | Lead |
|
|
106
106
|
| `/update-framework` | — | Sync bản npm mới | Lead |
|
|
107
107
|
|