@educa-corp/sdd-framework 0.9.4 → 0.9.6
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 +11 -1
- package/bin/lint-trace.js +599 -2
- package/bin/self-check.js +195 -0
- package/bin/trace-schema.json +2656 -1927
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/dev-gen-test.md +62 -0
- package/core/commands/generate-bdd.md +1 -0
- package/core/commands/generate-code.md +39 -2
- package/core/commands/generate-tech-docs.md +24 -5
- package/core/commands/map-testids.md +164 -7
- package/core/commands/qc-analyze.md +163 -9
- package/core/commands/qc-design-test.md +294 -2
- package/core/commands/qc-plan.md +57 -3
- package/core/commands/qc-report.md +76 -60
- package/core/commands/qc-review.md +102 -1
- package/core/commands/qc-run-test.md +194 -5
- package/core/commands/review-tech-docs.md +20 -0
- package/core/commands/validate-traces.md +17 -2
- package/core/modules/qc-playwright/stack-profile.yaml +1 -1
- package/core/rules/data-protection.md +52 -0
- package/core/rules/workflow.md +40 -0
- package/core/skills/qc/_shared/self-review-principles.md +112 -0
- package/core/skills/qc/qa-analyst/DOC_GAP.template.md +9 -1
- package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +33 -5
- package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +24 -0
- package/core/skills/qc/qa-planner/test-plan.md +7 -0
- package/core/skills/qc/qa-runner/e2e.md +2 -2
- package/core/skills/qc/qa-runner/functional/gui-feature.md +9 -3
- package/core/skills/qc/qa-runner/functional/gui-screen.md +9 -3
- package/core/skills/qc/qa-runner/integration.md +1 -1
- package/core/skills/qc/qa-runner/non-functional.md +1 -1
- package/core/skills/spec/SKILL.md +1 -1
- package/core/steps/context-loader.md +7 -2
- package/core/steps/gap-verify.md +67 -0
- package/core/steps/qc-scope.md +67 -11
- package/core/steps/qc-stamp.md +142 -0
- package/core/steps/report-footer.md +15 -7
- package/core/templates/feature.template +1 -0
- package/core/templates/tech-design.template.md +4 -3
- package/docs/01-getting-started/quickstart.md +4 -3
- package/docs/02-concepts/architecture.md +14 -0
- package/docs/02-concepts/glossary.md +8 -0
- package/docs/02-concepts/overview.md +3 -2
- package/docs/02-concepts/pipeline-steps/04-bdd.md +1 -1
- package/docs/02-concepts/pipeline-steps/05-tech-docs.md +21 -5
- package/docs/02-concepts/pipeline-steps/06-code.md +12 -2
- package/docs/02-concepts/pipeline-steps/08-qc-automation.md +60 -12
- package/docs/02-concepts/pipeline-steps/README.md +4 -3
- package/docs/02-concepts/traceability.md +2 -2
- package/docs/03-guides/architect.md +2 -2
- package/docs/03-guides/developer.md +5 -2
- package/docs/03-guides/tester-qa.md +17 -5
- package/docs/04-reference/commands.md +7 -4
- package/docs/04-reference/trace-schema.md +38 -0
- package/docs/explain/07-generate-tech-docs.md +5 -3
- package/docs/explain/08-review-tech-docs.md +15 -3
- package/docs/explain/09-generate-code.md +30 -4
- package/docs/explain/10-review-code.md +1 -1
- package/docs/explain/11-map-testids.md +10 -7
- package/docs/explain/12-dev-gen-test.md +1 -1
- package/docs/explain/15-qc-analyze.md +14 -2
- package/docs/explain/16-qc-plan.md +5 -1
- package/docs/explain/17-qc-design-test.md +26 -3
- package/docs/explain/18-qc-review.md +6 -2
- package/docs/explain/19-qc-run-test.md +29 -6
- package/docs/explain/20-qc-report.md +5 -2
- package/docs/explain/README.md +4 -1
- package/docs/plans/qc-surgery/00-nhat-ky.md +497 -0
- package/docs/plans/qc-surgery/01-checklist.md +92 -0
- package/docs/plans/qc-surgery/02-lo-trinh.md +266 -0
- package/docs/plans/qc-surgery/buoc/0-01-testid-attr-co-cho-o.md +157 -0
- package/docs/plans/qc-surgery/buoc/0-02-mot-nguon-cho-testid-attr.md +135 -0
- package/docs/plans/qc-surgery/buoc/0-03-skill-thoi-day-do-dom.md +167 -0
- package/docs/plans/qc-surgery/buoc/0-04-may-canh-hop-dong.md +173 -0
- package/docs/plans/qc-surgery/buoc/0-05-don-nhan-cot-va-2b.md +133 -0
- package/docs/plans/qc-surgery/buoc/0-06-hop-dong-truoc-code.md +226 -0
- package/docs/plans/qc-surgery/buoc/1-01-guard-br-tag.md +156 -0
- package/docs/plans/qc-surgery/buoc/1-02-guard-sc-coverage.md +153 -0
- package/docs/plans/qc-surgery/buoc/1-03-fail-3-nhan.md +176 -0
- package/docs/plans/qc-surgery/buoc/1-04-self-review-dung-chung.md +175 -0
- package/docs/plans/qc-surgery/buoc/1-05-spec-la-du-lieu.md +164 -0
- package/docs/plans/qc-surgery/buoc/1-06-gap-verify-du-bo.md +162 -0
- package/docs/plans/qc-surgery/buoc/README.md +85 -0
- package/docs/plans/qc-surgery/exec-d0-b1-testid-attr-header.md +147 -0
- package/docs/plans/qc-surgery/exec-d0-b2-thong-nhat-nguon-testid-attr.md +152 -0
- package/docs/plans/qc-surgery/exec-d0-b3-sua-skill-probe-dom.md +173 -0
- package/docs/plans/qc-surgery/exec-d0-b4-may-canh-4-5-6.md +168 -0
- package/docs/plans/qc-surgery/exec-d0-b5-don-nhan-lech.md +196 -0
- package/docs/plans/qc-surgery/exec-d0-b6-contract-truoc-code.md +350 -0
- package/docs/plans/qc-surgery/exec-d1-b1-guard-br-tag.md +129 -0
- package/docs/plans/qc-surgery/exec-d1-b2-guard-sc-coverage.md +159 -0
- package/docs/plans/qc-surgery/exec-d1-b3-fail-3-bucket.md +158 -0
- package/docs/plans/qc-surgery/exec-d1-b4-self-review-principles.md +145 -0
- package/docs/plans/qc-surgery/exec-d1-b5-noi-quy-spec-la-du-lieu.md +156 -0
- package/docs/plans/qc-surgery/exec-d1-b6-gap-verify-mo-rong.md +179 -0
- package/docs/plans/qc-surgery/exec-d2-b1-tach-qc-review.md +166 -0
- package/docs/plans/qc-surgery/exec-d2-b2-tach-qc-run-test-atomic.md +267 -0
- package/docs/plans/qc-surgery/exec-d2-b3-qc-automation-assess.md +198 -0
- package/docs/plans/qc-surgery/exec-d3-b1-qc-report-gate-decision.md +209 -0
- package/docs/plans/qc-surgery/exec-d4-b1-qc-design-testdata.md +146 -0
- package/docs/plans/qc-surgery/exec-d4-b2-qc-smoke-test.md +179 -0
- package/docs/plans/qc-surgery/exec-d4-b3-qc-metrics-va-lint.md +198 -0
- package/docs/plans/qc-surgery/exec-d4-b4-lint-spec-injection.md +199 -0
- package/package.json +1 -1
package/bin/trace-schema.json
CHANGED
|
@@ -1,1927 +1,2656 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$comment": [
|
|
3
|
-
"NGUỒN-SỰ-THẬT MÁY ĐỌC cho contract trace của framework. bin/self-check.js đối chiếu",
|
|
4
|
-
"file này với commands/*.tmpl + steps/*.md mỗi lần `npm run build`, và FAIL build khi lệch.",
|
|
5
|
-
"",
|
|
6
|
-
"Vì sao tồn tại: 19/23 GAP trong GAPS.md là cùng một lỗi — contract được phát biểu lại",
|
|
7
|
-
"bằng prose ở nhiều lệnh rồi lệch nhau qua từng lần sửa. Ca thuần khiết nhất là",
|
|
8
|
-
"@trace.sc_version: 3 consumer, 0 producer, tồn tại qua nhiều version mà không lệnh nào,",
|
|
9
|
-
"không cổng nào, không test nào phát hiện. Rule R1 dưới đây bắt đúng lớp lỗi đó.",
|
|
10
|
-
"",
|
|
11
|
-
"ĐỔI CONTRACT: sửa file này TRƯỚC, rồi mới sửa lệnh. Build fail nếu lệnh lệch schema.",
|
|
12
|
-
"Bản dành cho người đọc: docs/04-reference/trace-schema.md (giữ đồng bộ với file này).",
|
|
13
|
-
"",
|
|
14
|
-
"Định dạng JSON chứ không YAML vì package.json có ZERO dependency (npx chạy không cần",
|
|
15
|
-
"install) — thêm js-yaml chỉ để đọc một file cấu hình build-time là không đáng."
|
|
16
|
-
],
|
|
17
|
-
"actors": {
|
|
18
|
-
"$comment": "Tên logic → file nguồn. self-check tìm chuỗi field trong các file này.",
|
|
19
|
-
"generate-bdd": "commands/generate-bdd.tmpl",
|
|
20
|
-
"generate-code": "commands/generate-code.tmpl",
|
|
21
|
-
"generate-tech-docs": "commands/generate-tech-docs.tmpl",
|
|
22
|
-
"generate-prd": "commands/generate-prd.tmpl",
|
|
23
|
-
"generate-design-spec": "commands/generate-design-spec.tmpl",
|
|
24
|
-
"review-context": "commands/review-context.tmpl",
|
|
25
|
-
"review-tech-docs": "commands/review-tech-docs.tmpl",
|
|
26
|
-
"review-code": "commands/review-code.tmpl",
|
|
27
|
-
"validate-traces": "commands/validate-traces.tmpl",
|
|
28
|
-
"dev-gen-test": "commands/dev-gen-test.tmpl",
|
|
29
|
-
"dev-run-test": "commands/dev-run-test.tmpl",
|
|
30
|
-
"dev-smoke-test": "commands/dev-smoke-test.tmpl",
|
|
31
|
-
"qc-run-test": "commands/qc-run-test.tmpl",
|
|
32
|
-
"report-bug": "commands/report-bug.tmpl",
|
|
33
|
-
"propose-scenario": "commands/propose-scenario.tmpl",
|
|
34
|
-
"fix-bug": "commands/fix-bug.tmpl",
|
|
35
|
-
"refine-prd": "commands/refine-prd.tmpl",
|
|
36
|
-
"extend-prd": "commands/extend-prd.tmpl",
|
|
37
|
-
"sync": "commands/sync.tmpl",
|
|
38
|
-
"setup-ai-first": "commands/setup-ai-first.tmpl",
|
|
39
|
-
"generate-spec-manifest": "commands/generate-spec-manifest.tmpl",
|
|
40
|
-
"qc-analyze": "commands/qc-analyze.tmpl",
|
|
41
|
-
"qc-design-test": "commands/qc-design-test.tmpl",
|
|
42
|
-
"map-testids": "commands/map-testids.tmpl",
|
|
43
|
-
"debug": "commands/debug.tmpl",
|
|
44
|
-
"design-spec-template": "templates/design-spec.template.md",
|
|
45
|
-
"context-loader": "steps/context-loader.md",
|
|
46
|
-
"gate": "steps/gate.md",
|
|
47
|
-
"report-footer": "steps/report-footer.md",
|
|
48
|
-
"feature-template": "templates/feature.template",
|
|
49
|
-
"prd-template": "templates/prd.template.md",
|
|
50
|
-
"tech-design-template": "templates/tech-design.template.md"
|
|
51
|
-
},
|
|
52
|
-
"tags": [
|
|
53
|
-
{
|
|
54
|
-
"name": "@trace.sc_version",
|
|
55
|
-
"artifact": ".feature",
|
|
56
|
-
"scope": "scenario",
|
|
57
|
-
"shape": "semver-lite (1.0, 1.1)",
|
|
58
|
-
"written_by": [
|
|
59
|
-
"generate-bdd",
|
|
60
|
-
"feature-template"
|
|
61
|
-
],
|
|
62
|
-
"bumped_by": [
|
|
63
|
-
"generate-bdd",
|
|
64
|
-
"review-context"
|
|
65
|
-
],
|
|
66
|
-
"read_by": [
|
|
67
|
-
"generate-bdd",
|
|
68
|
-
"validate-traces",
|
|
69
|
-
"review-context"
|
|
70
|
-
],
|
|
71
|
-
"why": "Tín hiệu DUY NHẤT cho DRIFT (spec_ver != gen_ver). Không có producer = DRIFT chết."
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
"name": "@trace.bdd_version",
|
|
75
|
-
"artifact": ".feature",
|
|
76
|
-
"scope": "file",
|
|
77
|
-
"shape": "semver-lite scalar",
|
|
78
|
-
"written_by": [
|
|
79
|
-
"generate-bdd",
|
|
80
|
-
"feature-template"
|
|
81
|
-
],
|
|
82
|
-
"bumped_by": [
|
|
83
|
-
"generate-bdd",
|
|
84
|
-
"review-context"
|
|
85
|
-
],
|
|
86
|
-
"read_by": [
|
|
87
|
-
"generate-bdd",
|
|
88
|
-
"generate-code",
|
|
89
|
-
"generate-tech-docs",
|
|
90
|
-
"validate-traces",
|
|
91
|
-
"review-tech-docs",
|
|
92
|
-
"review-context"
|
|
93
|
-
],
|
|
94
|
-
"why": "Drift cấp file (Background/dataset/business-definition) mà sc_version không thấy."
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
"name": "@trace.bdd_versions",
|
|
98
|
-
"artifact": "tech-design.md",
|
|
99
|
-
"scope": "file",
|
|
100
|
-
"shape": "map theo platform (system=1.5, web=1.9)",
|
|
101
|
-
"written_by": [
|
|
102
|
-
"generate-tech-docs",
|
|
103
|
-
"tech-design-template"
|
|
104
|
-
],
|
|
105
|
-
"read_by": [
|
|
106
|
-
"generate-code",
|
|
107
|
-
"validate-traces",
|
|
108
|
-
"review-tech-docs"
|
|
109
|
-
],
|
|
110
|
-
"why": "Số NHIỀU, cố ý khác @trace.bdd_version (scalar) — cùng tên cho hai kiểu dữ liệu làm vỡ parser generic."
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
"name": "@trace.platform",
|
|
114
|
-
"artifact": ".feature",
|
|
115
|
-
"scope": "file",
|
|
116
|
-
"required": "always",
|
|
117
|
-
"values_from": "platform",
|
|
118
|
-
"written_by": [
|
|
119
|
-
"generate-bdd",
|
|
120
|
-
"feature-template"
|
|
121
|
-
],
|
|
122
|
-
"read_by": [
|
|
123
|
-
"generate-code",
|
|
124
|
-
"generate-tech-docs",
|
|
125
|
-
"review-context",
|
|
126
|
-
"context-loader"
|
|
127
|
-
],
|
|
128
|
-
"why": "Quyết BE/FE ở generate-code (cấm fallback platform_type) + tên sổ trace + lookup design-spec. Lưu ý: validate-traces và report-bug KHÔNG đọc tag này — chúng suy platform từ TÊN FILE .tsv ({UC-ID}-{platform}.tsv), nên không phải consumer của tag."
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
"name": "@trace.prd_version",
|
|
132
|
-
"artifact": ".feature + code",
|
|
133
|
-
"scope": "file + method",
|
|
134
|
-
"written_by": [
|
|
135
|
-
"generate-bdd",
|
|
136
|
-
"generate-code",
|
|
137
|
-
"feature-template"
|
|
138
|
-
],
|
|
139
|
-
"read_by": [
|
|
140
|
-
"generate-bdd",
|
|
141
|
-
"validate-traces",
|
|
142
|
-
"review-context"
|
|
143
|
-
],
|
|
144
|
-
"why": "Nguồn của PRD_DRIFT (validate-traces Step 4 so 3 tầng: PRD file, TSV, tag trong code)."
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
"name": "@trace.implements",
|
|
148
|
-
"artifact": "code",
|
|
149
|
-
"scope": "method",
|
|
150
|
-
"shape": "{UC-ID}-SC{N}",
|
|
151
|
-
"written_by": [
|
|
152
|
-
"generate-code",
|
|
153
|
-
"setup-ai-first"
|
|
154
|
-
],
|
|
155
|
-
"read_by": [
|
|
156
|
-
"validate-traces",
|
|
157
|
-
"review-code",
|
|
158
|
-
"dev-gen-test",
|
|
159
|
-
"dev-smoke-test",
|
|
160
|
-
"fix-bug"
|
|
161
|
-
],
|
|
162
|
-
"why": "Khoá chính của trace ở tầng code. Tra bằng khớp chuỗi CHÍNH XÁC → cấm trỏ thư mục."
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
"name": "@trace.source",
|
|
166
|
-
"artifact": "code",
|
|
167
|
-
"scope": "method",
|
|
168
|
-
"shape": "{specs_dir}/{domain}/{prd-slug}/bdd/{platform}/{UC-ID}-{slug}.feature",
|
|
169
|
-
"written_by": [
|
|
170
|
-
"generate-code",
|
|
171
|
-
"setup-ai-first"
|
|
172
|
-
],
|
|
173
|
-
"read_by": [
|
|
174
|
-
"review-code"
|
|
175
|
-
],
|
|
176
|
-
"why": "Con trỏ ngược về spec. PHẢI gồm segment {platform}."
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
"name": "@trace.tech_doc_revision",
|
|
180
|
-
"artifact": "code",
|
|
181
|
-
"scope": "method",
|
|
182
|
-
"written_by": [
|
|
183
|
-
"generate-code"
|
|
184
|
-
],
|
|
185
|
-
"read_by": [
|
|
186
|
-
"review-code"
|
|
187
|
-
],
|
|
188
|
-
"why": "Ghi revision tech-doc mà method này được sinh theo. BẤT ĐỐI XỨNG ĐÃ BIẾT: validate-traces Step 5 tính TECHDOC_DRIFT từ cột TSV tech_doc_revision chứ không từ tag này (khác Step 4, có so tag @trace.prd_version trong code). Nên hiện chỉ review-code kiểm sự CÓ MẶT của nó. Muốn đối xứng thì Step 5 phải đọc thêm tag trong code."
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
"name": "@trace.verifies",
|
|
192
|
-
"artifact": "test",
|
|
193
|
-
"scope": "method",
|
|
194
|
-
"shape": "{UC-ID}-SC{N}",
|
|
195
|
-
"written_by": [
|
|
196
|
-
"dev-gen-test",
|
|
197
|
-
"qc-run-test",
|
|
198
|
-
"fix-bug"
|
|
199
|
-
],
|
|
200
|
-
"read_by": [
|
|
201
|
-
"validate-traces",
|
|
202
|
-
"review-code",
|
|
203
|
-
"dev-run-test",
|
|
204
|
-
"qc-run-test"
|
|
205
|
-
],
|
|
206
|
-
"why": "Khớp test → sc_id khi ghi test_count/dev_selftest/qc_status."
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
"name": "@trace.scenario",
|
|
210
|
-
"artifact": ".feature",
|
|
211
|
-
"scope": "scenario",
|
|
212
|
-
"shape": "{UC-ID}-SC{N}",
|
|
213
|
-
"written_by": [
|
|
214
|
-
"generate-bdd",
|
|
215
|
-
"propose-scenario",
|
|
216
|
-
"feature-template"
|
|
217
|
-
],
|
|
218
|
-
"read_by": [
|
|
219
|
-
"generate-bdd",
|
|
220
|
-
"review-context"
|
|
221
|
-
],
|
|
222
|
-
"why": "Sinh sc_id cho row TSV. Thiếu nó = scenario vô hình với toàn bộ coverage."
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
"name": "@trace.status",
|
|
226
|
-
"artifact": ".feature + tech-design.md",
|
|
227
|
-
"scope": "file",
|
|
228
|
-
"values_from": "approval_status",
|
|
229
|
-
"written_by": [
|
|
230
|
-
"feature-template",
|
|
231
|
-
"review-context",
|
|
232
|
-
"review-tech-docs",
|
|
233
|
-
"generate-tech-docs",
|
|
234
|
-
"tech-design-template"
|
|
235
|
-
],
|
|
236
|
-
"read_by": [
|
|
237
|
-
"generate-code",
|
|
238
|
-
"validate-traces",
|
|
239
|
-
"review-tech-docs"
|
|
240
|
-
],
|
|
241
|
-
"why": "Cổng duyệt: DS1 của generate-code, và uc_status sync từ đây."
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
"name": "@trace.revision",
|
|
245
|
-
"artifact": "tech-design.md",
|
|
246
|
-
"scope": "file",
|
|
247
|
-
"shape": "integer",
|
|
248
|
-
"written_by": [
|
|
249
|
-
"generate-tech-docs",
|
|
250
|
-
"review-tech-docs",
|
|
251
|
-
"tech-design-template"
|
|
252
|
-
],
|
|
253
|
-
"read_by": [
|
|
254
|
-
"generate-code",
|
|
255
|
-
"validate-traces"
|
|
256
|
-
],
|
|
257
|
-
"why": "Nguồn của tech_doc_revision + TECHDOC_DRIFT."
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
"name": "@trace.api_source",
|
|
261
|
-
"artifact": ".feature + tech-design.md",
|
|
262
|
-
"scope": "file",
|
|
263
|
-
"written_by": [
|
|
264
|
-
"generate-bdd",
|
|
265
|
-
"tech-design-template"
|
|
266
|
-
],
|
|
267
|
-
"read_by": [
|
|
268
|
-
"review-tech-docs",
|
|
269
|
-
"review-context"
|
|
270
|
-
],
|
|
271
|
-
"why": "existing → bỏ cổng T7 + skip System BDD Synthesis S1-S3."
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
"name": "@trace.stub",
|
|
275
|
-
"artifact": "code",
|
|
276
|
-
"scope": "method",
|
|
277
|
-
"written_by": [
|
|
278
|
-
"generate-code"
|
|
279
|
-
],
|
|
280
|
-
"read_by": [
|
|
281
|
-
"validate-traces",
|
|
282
|
-
"review-code"
|
|
283
|
-
],
|
|
284
|
-
"why": "Method trắng nội-feature. Nguồn của STUB_UNRESOLVED."
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
"name": "@trace.mock_for",
|
|
288
|
-
"artifact": "code",
|
|
289
|
-
"scope": "class",
|
|
290
|
-
"written_by": [
|
|
291
|
-
"generate-code"
|
|
292
|
-
],
|
|
293
|
-
"read_by": [
|
|
294
|
-
"generate-code"
|
|
295
|
-
],
|
|
296
|
-
"why": "Đánh dấu layer mock của FE `--phase=ui` thuộc UC nào. `--phase=integration` dò lại chính tag này để biết mock nào phải thay bằng adapter thật — vừa ghi vừa đọc bởi cùng lệnh ở HAI phase khác nhau, đó là đúng."
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
"name": "@trace.mock_source",
|
|
300
|
-
"artifact": "code",
|
|
301
|
-
"scope": "class",
|
|
302
|
-
"values": "contract | system-bdd",
|
|
303
|
-
"written_by": [
|
|
304
|
-
"generate-code"
|
|
305
|
-
],
|
|
306
|
-
"read_by": [
|
|
307
|
-
"generate-code"
|
|
308
|
-
],
|
|
309
|
-
"why": "Shape của mock suy từ đâu. `system-bdd` = infer từ behavior (KHÔNG phải full request/response shape) → phase integration phải dự kiến điều chỉnh; `contract` = lấy từ §4 tech-doc, khớp sẵn."
|
|
310
|
-
},
|
|
311
|
-
{
|
|
312
|
-
"name": "@trace.system_bdd",
|
|
313
|
-
"artifact": "code",
|
|
314
|
-
"scope": "class",
|
|
315
|
-
"written_by": [
|
|
316
|
-
"generate-code"
|
|
317
|
-
],
|
|
318
|
-
"read_by": [],
|
|
319
|
-
"allow_no_reader": "Con trỏ tới System BDD mà mock được dựng theo. Nhãn truy vết cho người đọc + reviewer; không có consumer tự động (phase integration route bằng @trace.mock_for/@trace.mock_source).",
|
|
320
|
-
"why": "Ghi mock này dựng theo file System BDD nào."
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
"name": "@trace.be_contract",
|
|
324
|
-
"artifact": "code",
|
|
325
|
-
"scope": "class",
|
|
326
|
-
"written_by": [
|
|
327
|
-
"generate-code"
|
|
328
|
-
],
|
|
329
|
-
"read_by": [],
|
|
330
|
-
"allow_no_reader": "CHỈ có khi mock_source=contract — ghi tech-doc nào cấp shape. Nhãn truy vết, không có consumer tự động.",
|
|
331
|
-
"why": "Con trỏ tới tech-doc cấp shape cho mock."
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
"name": "@trace.root_cause",
|
|
335
|
-
"artifact": "code",
|
|
336
|
-
"scope": "method",
|
|
337
|
-
"written_by": [
|
|
338
|
-
"fix-bug"
|
|
339
|
-
],
|
|
340
|
-
"read_by": [],
|
|
341
|
-
"allow_no_reader": "Nhãn cho người đọc code — mô tả ngắn nguyên nhân gốc của bug đã fix. Cùng nhóm với @trace.fixes.",
|
|
342
|
-
"why": "Ghi lại nguyên nhân gốc tại chỗ sửa."
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
"name": "@trace.regression",
|
|
346
|
-
"artifact": "test",
|
|
347
|
-
"scope": "method",
|
|
348
|
-
"written_by": [
|
|
349
|
-
"fix-bug"
|
|
350
|
-
],
|
|
351
|
-
"read_by": [],
|
|
352
|
-
"allow_no_reader": "Đánh dấu test hồi quy sinh kèm bản fix. Nhãn cho người đọc; test_count/test_classes trong TSV mới là đường máy đọc (G7).",
|
|
353
|
-
"why": "Nhận diện test hồi quy của một ticket."
|
|
354
|
-
},
|
|
355
|
-
{
|
|
356
|
-
"name": "@trace.title",
|
|
357
|
-
"artifact": ".feature",
|
|
358
|
-
"scope": "file",
|
|
359
|
-
"written_by": [
|
|
360
|
-
"feature-template"
|
|
361
|
-
],
|
|
362
|
-
"read_by": [
|
|
363
|
-
"review-context"
|
|
364
|
-
],
|
|
365
|
-
"why": "Tên feature dạng người đọc. review-context B5 Nhóm B chỉ kiểm CÓ MẶT, không kiểm giá trị."
|
|
366
|
-
},
|
|
367
|
-
{
|
|
368
|
-
"name": "@trace.author",
|
|
369
|
-
"artifact": ".feature",
|
|
370
|
-
"scope": "file",
|
|
371
|
-
"written_by": [
|
|
372
|
-
"feature-template"
|
|
373
|
-
],
|
|
374
|
-
"read_by": [
|
|
375
|
-
"review-context"
|
|
376
|
-
],
|
|
377
|
-
"why": "Nguồn gốc file (`AI-generated`). Chỉ kiểm có mặt — xem @trace.title."
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
"name": "@trace.created_at",
|
|
381
|
-
"artifact": ".feature",
|
|
382
|
-
"scope": "file",
|
|
383
|
-
"written_by": [
|
|
384
|
-
"feature-template"
|
|
385
|
-
],
|
|
386
|
-
"read_by": [
|
|
387
|
-
"review-context"
|
|
388
|
-
],
|
|
389
|
-
"why": "Ngày tạo file. Chỉ kiểm có mặt — xem @trace.title. KHÁC last_updated của TSV (cái đó là trạng thái, cái này là gốc)."
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
"name": "@trace.generated_at",
|
|
393
|
-
"artifact": "tech-design.md",
|
|
394
|
-
"scope": "file",
|
|
395
|
-
"written_by": [
|
|
396
|
-
"tech-design-template"
|
|
397
|
-
],
|
|
398
|
-
"read_by": [],
|
|
399
|
-
"allow_no_reader": "Ngày sinh tech-doc. Drift của tech-doc đo bằng @trace.revision (integer), KHÔNG bằng ngày — nên field này thuần thông tin cho người đọc.",
|
|
400
|
-
"why": "Ngày sinh tech-doc, dạng người đọc."
|
|
401
|
-
},
|
|
402
|
-
{
|
|
403
|
-
"name": "@trace.business_rules",
|
|
404
|
-
"artifact": ".feature",
|
|
405
|
-
"scope": "scenario",
|
|
406
|
-
"shape": "{TICKET-ID}-UC{N}-BR{m}, …",
|
|
407
|
-
"written_by": [
|
|
408
|
-
"generate-bdd",
|
|
409
|
-
"feature-template",
|
|
410
|
-
"propose-scenario"
|
|
411
|
-
],
|
|
412
|
-
"read_by": [
|
|
413
|
-
"review-context"
|
|
414
|
-
],
|
|
415
|
-
"$reader_note": "generate-tech-docs đọc BR ID từ THÂN scenario (`BR{m}`), không đọc tag này — nên nó không phải consumer.",
|
|
416
|
-
"why": "Link scenario ↔ Business Rule của PRD. BR đánh số LIÊN TỤC toàn PRD (không reset theo UC — G14), nên ID ở đây phải lấy NGUYÊN từ PRD §3. Mở cột bảng BR trên PRD đã có BDD sẽ làm churn ID và phá link này."
|
|
417
|
-
},
|
|
418
|
-
{
|
|
419
|
-
"name": "@trace.dataset",
|
|
420
|
-
"artifact": ".feature",
|
|
421
|
-
"scope": "file",
|
|
422
|
-
"$producer_note": "CHỈ feature-template — nó được {{include}} nướng cứng vào generate-bdd lúc build, nên generate-bdd không nhắc tên field này ở prose của chính nó. Khai thêm generate-bdd sẽ làm R3 fail.",
|
|
423
|
-
"written_by": [
|
|
424
|
-
"feature-template"
|
|
425
|
-
],
|
|
426
|
-
"read_by": [
|
|
427
|
-
"review-context",
|
|
428
|
-
"validate-traces"
|
|
429
|
-
],
|
|
430
|
-
"why": "File testdata dùng chung của feature. Đổi nó là thay đổi CẤP FILE mà sc_version không thấy — chính vì vậy Step 5c liệt nó vào nguồn của BDD_DRIFT."
|
|
431
|
-
},
|
|
432
|
-
{
|
|
433
|
-
"name": "@trace.prd",
|
|
434
|
-
"artifact": ".feature",
|
|
435
|
-
"scope": "file",
|
|
436
|
-
"shape": "{TICKET-ID}",
|
|
437
|
-
"$producer_note": "CHỈ feature-template — xem @trace.dataset.",
|
|
438
|
-
"written_by": [
|
|
439
|
-
"feature-template"
|
|
440
|
-
],
|
|
441
|
-
"read_by": [
|
|
442
|
-
"review-context"
|
|
443
|
-
],
|
|
444
|
-
"why": "Con trỏ ngược .feature → PRD. Mang TICKET-ID chứ không phải path, vì tech-doc và trace cũng khoá theo TICKET-ID."
|
|
445
|
-
},
|
|
446
|
-
{
|
|
447
|
-
"name": "@trace.platforms",
|
|
448
|
-
"artifact": "tech-design.md",
|
|
449
|
-
"scope": "file",
|
|
450
|
-
"shape": "danh sách platform",
|
|
451
|
-
"written_by": [
|
|
452
|
-
"generate-tech-docs",
|
|
453
|
-
"tech-design-template"
|
|
454
|
-
],
|
|
455
|
-
"read_by": [
|
|
456
|
-
"review-tech-docs"
|
|
457
|
-
],
|
|
458
|
-
"why": "Số NHIỀU, cố ý khác @trace.platform (scalar, ở .feature) — cùng lý do như bdd_version vs bdd_versions (G15): tech-doc là doc GỘP phủ nhiều platform."
|
|
459
|
-
},
|
|
460
|
-
{
|
|
461
|
-
"name": "@trace.test_type",
|
|
462
|
-
"artifact": "test",
|
|
463
|
-
"scope": "method",
|
|
464
|
-
"written_by": [
|
|
465
|
-
"dev-gen-test"
|
|
466
|
-
],
|
|
467
|
-
"read_by": [],
|
|
468
|
-
"allow_no_reader": "NHÃN CHẾT — phát hiện khi khai schema (G30 lô 3). /dev-gen-test dán nó lên mọi test class nhưng KHÔNG lệnh nào đọc: dev-run-test chạy theo test_command của project, qc-* dùng stack riêng. Giữ vì nó là nhãn hữu ích cho người đọc code và là chỗ móc sẵn nếu sau này muốn chạy test theo loại (vd chỉ chạy unit ở pre-commit). Nếu 6 tháng nữa vẫn không consumer nào → bỏ hẳn thay vì để nợ.",
|
|
469
|
-
"why": "Phân loại test (unit/integration/e2e…). Hiện chỉ là nhãn cho người đọc."
|
|
470
|
-
},
|
|
471
|
-
{
|
|
472
|
-
"name": "@trace.testid_attr",
|
|
473
|
-
"artifact": "tech-design.md",
|
|
474
|
-
"scope": "file",
|
|
475
|
-
"written_by": [
|
|
476
|
-
"map-testids"
|
|
477
|
-
],
|
|
478
|
-
"read_by": [
|
|
479
|
-
"generate-code",
|
|
480
|
-
"qc-run-test",
|
|
481
|
-
"qc-design-test"
|
|
482
|
-
],
|
|
483
|
-
"$history_note": "G30 lô 3 phát hiện field này TỰ MÔ TẢ là contract FE↔QC nhưng chỉ nửa FE (generate-code) đọc — QC tự suy tên thuộc tính từ platform. G37 nối nửa QC: qc-run-test đọc để CẤU HÌNH test-id attribute (Playwright get_by_test_id mặc định dò `data-testid`; dự án dùng `data-test`/`data-qa` sẽ trượt 100% locator nếu không set), qc-design-test ghi lại vào metadata .Test.md để reviewer đối chiếu.",
|
|
484
|
-
"why": "Tên thuộc tính test-id của stack — contract FE↔QC. FE emit theo nó (generate-code), QC cấu hình locator theo nó (qc-run-test). Suy từ platform thay vì đọc field = phát biểu lại sự thật đã ghi ở nơi khác, và hỏng IM LẶNG: test fail 'element not found' trông y hệt bug sản phẩm."
|
|
485
|
-
},
|
|
486
|
-
{
|
|
487
|
-
"name": "@trace.domain",
|
|
488
|
-
"artifact": ".feature + tech-design.md",
|
|
489
|
-
"scope": "file",
|
|
490
|
-
"written_by": [
|
|
491
|
-
"generate-bdd",
|
|
492
|
-
"feature-template",
|
|
493
|
-
"tech-design-template"
|
|
494
|
-
],
|
|
495
|
-
"read_by": [
|
|
496
|
-
"context-loader",
|
|
497
|
-
"review-context",
|
|
498
|
-
"review-tech-docs",
|
|
499
|
-
"generate-spec-manifest",
|
|
500
|
-
"setup-ai-first"
|
|
501
|
-
],
|
|
502
|
-
"why": "Khoá ĐỊNH TUYẾN. context-loader Bước 1.5 đọc nó từ frontmatter target để chọn service submodule — sai là ghi code/trace nhầm repo mà không báo gì."
|
|
503
|
-
},
|
|
504
|
-
{
|
|
505
|
-
"name": "@trace.id",
|
|
506
|
-
"artifact": ".feature + tech-design.md",
|
|
507
|
-
"scope": "file",
|
|
508
|
-
"shape": "{TICKET-ID}-UC{N}",
|
|
509
|
-
"written_by": [
|
|
510
|
-
"feature-template",
|
|
511
|
-
"tech-design-template"
|
|
512
|
-
],
|
|
513
|
-
"read_by": [
|
|
514
|
-
"generate-code",
|
|
515
|
-
"generate-tech-docs",
|
|
516
|
-
"qc-analyze",
|
|
517
|
-
"review-context"
|
|
518
|
-
],
|
|
519
|
-
"why": "UC-ID của file. generate-code đọc nó để chốt Scope Lock (implement ĐÚNG UC này, không lan sang .feature khác)."
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
"name": "@trace.module",
|
|
523
|
-
"artifact": ".feature + tech-design.md",
|
|
524
|
-
"scope": "file",
|
|
525
|
-
"written_by": [
|
|
526
|
-
"feature-template",
|
|
527
|
-
"tech-design-template"
|
|
528
|
-
],
|
|
529
|
-
"read_by": [
|
|
530
|
-
"dev-gen-test",
|
|
531
|
-
"generate-tech-docs",
|
|
532
|
-
"review-context"
|
|
533
|
-
],
|
|
534
|
-
"why": "Stack module của service sở hữu. dev-gen-test dùng để chọn test pattern. Giá trị `unknown` ở spec repo mode là HỢP LỆ — review-context không được flag."
|
|
535
|
-
},
|
|
536
|
-
{
|
|
537
|
-
"name": "@trace.ucs",
|
|
538
|
-
"artifact": "tech-design.md",
|
|
539
|
-
"scope": "file",
|
|
540
|
-
"shape": "danh sách UC-ID",
|
|
541
|
-
"written_by": [
|
|
542
|
-
"generate-tech-docs",
|
|
543
|
-
"tech-design-template"
|
|
544
|
-
],
|
|
545
|
-
"read_by": [
|
|
546
|
-
"review-tech-docs",
|
|
547
|
-
"gate"
|
|
548
|
-
],
|
|
549
|
-
"why": "Tech-doc là doc GỘP cấp PRD — đây là danh sách UC nó phủ. Cần vì tên file mang {TICKET-ID} chứ không mang {UC-ID} (G10): gate phải tách TICKET-ID rồi glob, và dùng field này để biết doc có phủ UC đang hỏi không."
|
|
550
|
-
},
|
|
551
|
-
{
|
|
552
|
-
"name": "@trace.seam_port",
|
|
553
|
-
"artifact": "code",
|
|
554
|
-
"scope": "class",
|
|
555
|
-
"written_by": [
|
|
556
|
-
"generate-code"
|
|
557
|
-
],
|
|
558
|
-
"read_by": [
|
|
559
|
-
"review-code"
|
|
560
|
-
],
|
|
561
|
-
"why": "Tên port mà class stub đang giả lập. Đi CẶP với @trace.seam_pending — review-code kiểm cả hai phải có mặt cùng dòng `PENDING` trong _seams.tsv. validate-traces Step 5b nhận diện seam qua @trace.seam_pending + cột `name` của sổ, KHÔNG đọc tag này."
|
|
562
|
-
},
|
|
563
|
-
{
|
|
564
|
-
"name": "@trace.stub_owner",
|
|
565
|
-
"artifact": "code",
|
|
566
|
-
"scope": "method",
|
|
567
|
-
"written_by": [
|
|
568
|
-
"generate-code"
|
|
569
|
-
],
|
|
570
|
-
"read_by": [
|
|
571
|
-
"validate-traces",
|
|
572
|
-
"review-code"
|
|
573
|
-
],
|
|
574
|
-
"why": "UC lẽ ra phải lấp method trắng này. Step 5b hỏi 'owner đã gen chưa' để quyết STUB_PENDING (ⓘ) vs STUB_UNRESOLVED (🔴 chặn PR). Mất tag = mất luôn phép phân biệt đó → hoặc báo động oan mọi stub, hoặc bỏ sót hàm trắng mồ côi."
|
|
575
|
-
},
|
|
576
|
-
{
|
|
577
|
-
"name": "@trace.stub_for",
|
|
578
|
-
"artifact": "code",
|
|
579
|
-
"scope": "method",
|
|
580
|
-
"written_by": [
|
|
581
|
-
"generate-code"
|
|
582
|
-
],
|
|
583
|
-
"read_by": [
|
|
584
|
-
"validate-traces",
|
|
585
|
-
"review-code"
|
|
586
|
-
],
|
|
587
|
-
"why": "Trách nhiệm mà method trắng này đang giữ chỗ. Step 5b dùng nó để dò 'có hàm THẬT song song cùng trách nhiệm không' — dấu hiệu Fill-before-create đã trượt (BDD owner đẻ hàm mới thay vì lấp hàm cũ)."
|
|
588
|
-
},
|
|
589
|
-
{
|
|
590
|
-
"name": "@trace.sign_off",
|
|
591
|
-
"artifact": "tech-design.md",
|
|
592
|
-
"scope": "file",
|
|
593
|
-
"written_by": [
|
|
594
|
-
"review-tech-docs"
|
|
595
|
-
],
|
|
596
|
-
"read_by": [
|
|
597
|
-
"review-tech-docs"
|
|
598
|
-
],
|
|
599
|
-
"why": "Cổng T7 — xác nhận cross-team của tech-doc system BDD. Vừa ghi vừa đọc bởi cùng một lệnh là ĐÚNG (nó là sổ trạng thái nội bộ của cổng đó, không phải contract liên lệnh). LƯU Ý: tech-design.template.md KHÔNG phát ra field này — review-tech-docs tự thêm khi thiếu, nên template không phải producer."
|
|
600
|
-
},
|
|
601
|
-
{
|
|
602
|
-
"name": "@trace.seam_pending",
|
|
603
|
-
"artifact": "code",
|
|
604
|
-
"scope": "class",
|
|
605
|
-
"written_by": [
|
|
606
|
-
"generate-code"
|
|
607
|
-
],
|
|
608
|
-
"read_by": [
|
|
609
|
-
"validate-traces",
|
|
610
|
-
"review-code"
|
|
611
|
-
],
|
|
612
|
-
"why": "Port cross-UC chưa có hàng thật. Nguồn của SEAM_UNWIRED."
|
|
613
|
-
},
|
|
614
|
-
{
|
|
615
|
-
"name": "@trace.service",
|
|
616
|
-
"artifact": ".feature",
|
|
617
|
-
"scope": "file",
|
|
618
|
-
"written_by": [
|
|
619
|
-
"generate-bdd",
|
|
620
|
-
"feature-template"
|
|
621
|
-
],
|
|
622
|
-
"read_by": [
|
|
623
|
-
"generate-bdd",
|
|
624
|
-
"dev-gen-test",
|
|
625
|
-
"generate-tech-docs",
|
|
626
|
-
"review-context"
|
|
627
|
-
],
|
|
628
|
-
"why": "Nguồn DUY NHẤT của cột TSV `service` (cột 23) — trace gộp không tách theo service nên thiếu tag này là mất hẳn thông tin sở hữu ở cấp row. BẮT BUỘC mọi mode từ v0.4.3 (trước đó feature.template chủ động bỏ ở spec repo mode, và review-context xếp nó vào Nhóm C có-điều-kiện)."
|
|
629
|
-
},
|
|
630
|
-
{
|
|
631
|
-
"name": "@trace.design_spec_version",
|
|
632
|
-
"artifact": "code",
|
|
633
|
-
"scope": "method",
|
|
634
|
-
"written_by": [
|
|
635
|
-
"generate-code"
|
|
636
|
-
],
|
|
637
|
-
"read_by": [
|
|
638
|
-
"validate-traces",
|
|
639
|
-
"review-code"
|
|
640
|
-
],
|
|
641
|
-
"why": "Nguồn của DESIGNSPEC_DRIFT (Step 5d). CHỈ FE/App — bỏ hẳn dòng tag với system/backend."
|
|
642
|
-
},
|
|
643
|
-
{
|
|
644
|
-
"name": "@trace.fixes",
|
|
645
|
-
"artifact": "code",
|
|
646
|
-
"scope": "method",
|
|
647
|
-
"written_by": [
|
|
648
|
-
"fix-bug"
|
|
649
|
-
],
|
|
650
|
-
"read_by": [],
|
|
651
|
-
"allow_no_reader": "Nhãn cho người đọc code, không có consumer tự động."
|
|
652
|
-
}
|
|
653
|
-
],
|
|
654
|
-
"tsv_columns": [
|
|
655
|
-
{
|
|
656
|
-
"n": 1,
|
|
657
|
-
"name": "sc_id",
|
|
658
|
-
"written_by": [
|
|
659
|
-
"generate-bdd"
|
|
660
|
-
],
|
|
661
|
-
"read_by": [
|
|
662
|
-
"validate-traces",
|
|
663
|
-
"generate-code",
|
|
664
|
-
"dev-gen-test",
|
|
665
|
-
"dev-run-test",
|
|
666
|
-
"qc-run-test",
|
|
667
|
-
"report-bug",
|
|
668
|
-
"fix-bug"
|
|
669
|
-
]
|
|
670
|
-
},
|
|
671
|
-
{
|
|
672
|
-
"n": 2,
|
|
673
|
-
"name": "sc_title",
|
|
674
|
-
"written_by": [
|
|
675
|
-
"generate-bdd"
|
|
676
|
-
],
|
|
677
|
-
"read_by": [
|
|
678
|
-
"validate-traces"
|
|
679
|
-
]
|
|
680
|
-
},
|
|
681
|
-
{
|
|
682
|
-
"n": 3,
|
|
683
|
-
"name": "spec_ver",
|
|
684
|
-
"written_by": [
|
|
685
|
-
"generate-bdd",
|
|
686
|
-
"validate-traces",
|
|
687
|
-
"review-context"
|
|
688
|
-
],
|
|
689
|
-
"read_by": [
|
|
690
|
-
"validate-traces",
|
|
691
|
-
"generate-code"
|
|
692
|
-
]
|
|
693
|
-
},
|
|
694
|
-
{
|
|
695
|
-
"n": 4,
|
|
696
|
-
"name": "gen_ver",
|
|
697
|
-
"written_by": [
|
|
698
|
-
"generate-code",
|
|
699
|
-
"validate-traces"
|
|
700
|
-
],
|
|
701
|
-
"read_by": [
|
|
702
|
-
"validate-traces",
|
|
703
|
-
"generate-bdd"
|
|
704
|
-
]
|
|
705
|
-
},
|
|
706
|
-
{
|
|
707
|
-
"n": 5,
|
|
708
|
-
"name": "implemented_by",
|
|
709
|
-
"written_by": [
|
|
710
|
-
"generate-code",
|
|
711
|
-
"validate-traces"
|
|
712
|
-
],
|
|
713
|
-
"read_by": [
|
|
714
|
-
"validate-traces",
|
|
715
|
-
"generate-bdd"
|
|
716
|
-
]
|
|
717
|
-
},
|
|
718
|
-
{
|
|
719
|
-
"n": 6,
|
|
720
|
-
"name": "test_count",
|
|
721
|
-
"written_by": [
|
|
722
|
-
"dev-gen-test",
|
|
723
|
-
"fix-bug"
|
|
724
|
-
],
|
|
725
|
-
"read_by": [
|
|
726
|
-
"validate-traces",
|
|
727
|
-
"generate-bdd"
|
|
728
|
-
]
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
"n": 7,
|
|
732
|
-
"name": "test_classes",
|
|
733
|
-
"written_by": [
|
|
734
|
-
"dev-gen-test",
|
|
735
|
-
"fix-bug"
|
|
736
|
-
],
|
|
737
|
-
"read_by": [
|
|
738
|
-
"validate-traces",
|
|
739
|
-
"generate-bdd"
|
|
740
|
-
]
|
|
741
|
-
},
|
|
742
|
-
{
|
|
743
|
-
"n": 8,
|
|
744
|
-
"name": "dev_selftest",
|
|
745
|
-
"$invalidated_by_comment": [
|
|
746
|
-
"PRODUCER vs INVALIDATOR — hai vai khác nhau, cùng nằm trong written_by.",
|
|
747
|
-
"Chủ sở hữu (ghi giá trị KHẲNG ĐỊNH pass/fail): dev-run-test.",
|
|
748
|
-
"Invalidator (chỉ được hạ về not_run/— khi giá trị cũ HẾT ĐÚNG): generate-bdd (spec đổi),",
|
|
749
|
-
"generate-code (lấp stub hoặc sửa method do DRIFT), fix-bug (code đổi), dev-gen-test (test mới).",
|
|
750
|
-
"Luật đầy đủ: rules/workflow.md §Trace Contract — 'Làm mất hiệu lực ≠ ghi đè'.",
|
|
751
|
-
"Vì sao cần: giữ một 'pass' sinh ra từ spec đã bị sửa là BÁO CÁO SAI. Trước G28 chỉ",
|
|
752
|
-
"nhánh lấp-stub hạ cờ, nên chuỗi spec-đổi → DRIFT → regen → OK kết thúc bằng dashboard",
|
|
753
|
-
"xanh hoàn toàn trên một hành vi chưa từng được test."
|
|
754
|
-
],
|
|
755
|
-
"written_by": [
|
|
756
|
-
"dev-run-test",
|
|
757
|
-
"dev-gen-test",
|
|
758
|
-
"generate-code",
|
|
759
|
-
"generate-bdd",
|
|
760
|
-
"fix-bug"
|
|
761
|
-
],
|
|
762
|
-
"read_by": [
|
|
763
|
-
"validate-traces",
|
|
764
|
-
"qc-run-test"
|
|
765
|
-
]
|
|
766
|
-
},
|
|
767
|
-
{
|
|
768
|
-
"n": 9,
|
|
769
|
-
"name": "dev_selftest_at",
|
|
770
|
-
"$comment": "Chủ: dev-run-test. Invalidator (hạ về —): generate-bdd · generate-code · fix-bug. Xem dev_selftest.",
|
|
771
|
-
"written_by": [
|
|
772
|
-
"dev-run-test",
|
|
773
|
-
"generate-code",
|
|
774
|
-
"generate-bdd",
|
|
775
|
-
"fix-bug"
|
|
776
|
-
],
|
|
777
|
-
"read_by": [
|
|
778
|
-
"validate-traces",
|
|
779
|
-
"qc-run-test"
|
|
780
|
-
]
|
|
781
|
-
},
|
|
782
|
-
{
|
|
783
|
-
"n": 10,
|
|
784
|
-
"name": "qc_status",
|
|
785
|
-
"$comment": "Chủ (ghi pass/fail/skip): qc-run-test — DUY NHẤT. Invalidator (chỉ hạ về not_run khi spec/code vừa đổi): generate-bdd · generate-code. Xem dev_selftest + rules/workflow.md 'Làm mất hiệu lực ≠ ghi đè'.",
|
|
786
|
-
"written_by": [
|
|
787
|
-
"qc-run-test",
|
|
788
|
-
"generate-bdd",
|
|
789
|
-
"generate-code"
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
"
|
|
794
|
-
"
|
|
795
|
-
"
|
|
796
|
-
"
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
"
|
|
802
|
-
"
|
|
803
|
-
"
|
|
804
|
-
|
|
805
|
-
"
|
|
806
|
-
"generate-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
"
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
"
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
"
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
"
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
"
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
"
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
"
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
"
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
"
|
|
871
|
-
"
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
"
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
"
|
|
882
|
-
"
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
"
|
|
890
|
-
"
|
|
891
|
-
"
|
|
892
|
-
]
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
"
|
|
901
|
-
"
|
|
902
|
-
"
|
|
903
|
-
"review-
|
|
904
|
-
]
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
"
|
|
914
|
-
"
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
"
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
"
|
|
926
|
-
"validate-traces",
|
|
927
|
-
"generate-
|
|
928
|
-
]
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
"
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
"
|
|
947
|
-
"
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
"
|
|
951
|
-
"
|
|
952
|
-
"",
|
|
953
|
-
"
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
"",
|
|
961
|
-
"
|
|
962
|
-
"
|
|
963
|
-
"
|
|
964
|
-
"
|
|
965
|
-
"
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
"
|
|
969
|
-
"
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
"
|
|
973
|
-
"
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
"
|
|
981
|
-
"
|
|
982
|
-
"
|
|
983
|
-
"
|
|
984
|
-
"
|
|
985
|
-
"
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
"
|
|
994
|
-
]
|
|
995
|
-
},
|
|
996
|
-
{
|
|
997
|
-
"n":
|
|
998
|
-
"name": "
|
|
999
|
-
"
|
|
1000
|
-
"
|
|
1001
|
-
"
|
|
1002
|
-
"
|
|
1003
|
-
"
|
|
1004
|
-
"
|
|
1005
|
-
"
|
|
1006
|
-
"
|
|
1007
|
-
"
|
|
1008
|
-
],
|
|
1009
|
-
"
|
|
1010
|
-
"
|
|
1011
|
-
]
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
"
|
|
1024
|
-
"
|
|
1025
|
-
"
|
|
1026
|
-
"
|
|
1027
|
-
"
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
"
|
|
1031
|
-
]
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
"
|
|
1037
|
-
"
|
|
1038
|
-
"
|
|
1039
|
-
],
|
|
1040
|
-
"
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
"
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
"
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
"
|
|
1070
|
-
"
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
"
|
|
1075
|
-
"
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
"
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
"
|
|
1095
|
-
"
|
|
1096
|
-
"
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
"
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
"
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
"
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
"
|
|
1125
|
-
"",
|
|
1126
|
-
"
|
|
1127
|
-
"
|
|
1128
|
-
"
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
"
|
|
1135
|
-
"
|
|
1136
|
-
"
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
"
|
|
1140
|
-
"
|
|
1141
|
-
"
|
|
1142
|
-
"webview"
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
"
|
|
1150
|
-
"
|
|
1151
|
-
"
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
"
|
|
1155
|
-
"
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
"
|
|
1161
|
-
"
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
"
|
|
1170
|
-
"
|
|
1171
|
-
"
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
"
|
|
1175
|
-
"
|
|
1176
|
-
]
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
"
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
"
|
|
1187
|
-
"
|
|
1188
|
-
"
|
|
1189
|
-
"
|
|
1190
|
-
"
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
"
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
"
|
|
1206
|
-
|
|
1207
|
-
"
|
|
1208
|
-
"
|
|
1209
|
-
"
|
|
1210
|
-
"
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
"
|
|
1217
|
-
"
|
|
1218
|
-
"
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
"
|
|
1283
|
-
""
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
{
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
"
|
|
1401
|
-
|
|
1402
|
-
"
|
|
1403
|
-
"
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
"
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
"
|
|
1416
|
-
]
|
|
1417
|
-
},
|
|
1418
|
-
{
|
|
1419
|
-
"
|
|
1420
|
-
"
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
"
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
"
|
|
1504
|
-
"
|
|
1505
|
-
"
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
"
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
"
|
|
1513
|
-
"
|
|
1514
|
-
"
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
"
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
"
|
|
1522
|
-
"
|
|
1523
|
-
"
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
"
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
"
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
]
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
"
|
|
1556
|
-
"
|
|
1557
|
-
"
|
|
1558
|
-
"
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
"
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
"
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
"
|
|
1582
|
-
"
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
"
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
"
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
"
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
"
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
"
|
|
1763
|
-
"
|
|
1764
|
-
"
|
|
1765
|
-
"
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
"
|
|
1769
|
-
"
|
|
1770
|
-
"
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
"
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
"
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
"
|
|
1811
|
-
"
|
|
1812
|
-
"",
|
|
1813
|
-
"
|
|
1814
|
-
"
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
"
|
|
1871
|
-
"
|
|
1872
|
-
"
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
"
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
"
|
|
1897
|
-
"
|
|
1898
|
-
"
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
"
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1
|
+
{
|
|
2
|
+
"$comment": [
|
|
3
|
+
"NGUỒN-SỰ-THẬT MÁY ĐỌC cho contract trace của framework. bin/self-check.js đối chiếu",
|
|
4
|
+
"file này với commands/*.tmpl + steps/*.md mỗi lần `npm run build`, và FAIL build khi lệch.",
|
|
5
|
+
"",
|
|
6
|
+
"Vì sao tồn tại: 19/23 GAP trong GAPS.md là cùng một lỗi — contract được phát biểu lại",
|
|
7
|
+
"bằng prose ở nhiều lệnh rồi lệch nhau qua từng lần sửa. Ca thuần khiết nhất là",
|
|
8
|
+
"@trace.sc_version: 3 consumer, 0 producer, tồn tại qua nhiều version mà không lệnh nào,",
|
|
9
|
+
"không cổng nào, không test nào phát hiện. Rule R1 dưới đây bắt đúng lớp lỗi đó.",
|
|
10
|
+
"",
|
|
11
|
+
"ĐỔI CONTRACT: sửa file này TRƯỚC, rồi mới sửa lệnh. Build fail nếu lệnh lệch schema.",
|
|
12
|
+
"Bản dành cho người đọc: docs/04-reference/trace-schema.md (giữ đồng bộ với file này).",
|
|
13
|
+
"",
|
|
14
|
+
"Định dạng JSON chứ không YAML vì package.json có ZERO dependency (npx chạy không cần",
|
|
15
|
+
"install) — thêm js-yaml chỉ để đọc một file cấu hình build-time là không đáng."
|
|
16
|
+
],
|
|
17
|
+
"actors": {
|
|
18
|
+
"$comment": "Tên logic → file nguồn. self-check tìm chuỗi field trong các file này.",
|
|
19
|
+
"generate-bdd": "commands/generate-bdd.tmpl",
|
|
20
|
+
"generate-code": "commands/generate-code.tmpl",
|
|
21
|
+
"generate-tech-docs": "commands/generate-tech-docs.tmpl",
|
|
22
|
+
"generate-prd": "commands/generate-prd.tmpl",
|
|
23
|
+
"generate-design-spec": "commands/generate-design-spec.tmpl",
|
|
24
|
+
"review-context": "commands/review-context.tmpl",
|
|
25
|
+
"review-tech-docs": "commands/review-tech-docs.tmpl",
|
|
26
|
+
"review-code": "commands/review-code.tmpl",
|
|
27
|
+
"validate-traces": "commands/validate-traces.tmpl",
|
|
28
|
+
"dev-gen-test": "commands/dev-gen-test.tmpl",
|
|
29
|
+
"dev-run-test": "commands/dev-run-test.tmpl",
|
|
30
|
+
"dev-smoke-test": "commands/dev-smoke-test.tmpl",
|
|
31
|
+
"qc-run-test": "commands/qc-run-test.tmpl",
|
|
32
|
+
"report-bug": "commands/report-bug.tmpl",
|
|
33
|
+
"propose-scenario": "commands/propose-scenario.tmpl",
|
|
34
|
+
"fix-bug": "commands/fix-bug.tmpl",
|
|
35
|
+
"refine-prd": "commands/refine-prd.tmpl",
|
|
36
|
+
"extend-prd": "commands/extend-prd.tmpl",
|
|
37
|
+
"sync": "commands/sync.tmpl",
|
|
38
|
+
"setup-ai-first": "commands/setup-ai-first.tmpl",
|
|
39
|
+
"generate-spec-manifest": "commands/generate-spec-manifest.tmpl",
|
|
40
|
+
"qc-analyze": "commands/qc-analyze.tmpl",
|
|
41
|
+
"qc-design-test": "commands/qc-design-test.tmpl",
|
|
42
|
+
"map-testids": "commands/map-testids.tmpl",
|
|
43
|
+
"debug": "commands/debug.tmpl",
|
|
44
|
+
"design-spec-template": "templates/design-spec.template.md",
|
|
45
|
+
"context-loader": "steps/context-loader.md",
|
|
46
|
+
"gate": "steps/gate.md",
|
|
47
|
+
"report-footer": "steps/report-footer.md",
|
|
48
|
+
"feature-template": "templates/feature.template",
|
|
49
|
+
"prd-template": "templates/prd.template.md",
|
|
50
|
+
"tech-design-template": "templates/tech-design.template.md"
|
|
51
|
+
},
|
|
52
|
+
"tags": [
|
|
53
|
+
{
|
|
54
|
+
"name": "@trace.sc_version",
|
|
55
|
+
"artifact": ".feature",
|
|
56
|
+
"scope": "scenario",
|
|
57
|
+
"shape": "semver-lite (1.0, 1.1)",
|
|
58
|
+
"written_by": [
|
|
59
|
+
"generate-bdd",
|
|
60
|
+
"feature-template"
|
|
61
|
+
],
|
|
62
|
+
"bumped_by": [
|
|
63
|
+
"generate-bdd",
|
|
64
|
+
"review-context"
|
|
65
|
+
],
|
|
66
|
+
"read_by": [
|
|
67
|
+
"generate-bdd",
|
|
68
|
+
"validate-traces",
|
|
69
|
+
"review-context"
|
|
70
|
+
],
|
|
71
|
+
"why": "Tín hiệu DUY NHẤT cho DRIFT (spec_ver != gen_ver). Không có producer = DRIFT chết."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "@trace.bdd_version",
|
|
75
|
+
"artifact": ".feature",
|
|
76
|
+
"scope": "file",
|
|
77
|
+
"shape": "semver-lite scalar",
|
|
78
|
+
"written_by": [
|
|
79
|
+
"generate-bdd",
|
|
80
|
+
"feature-template"
|
|
81
|
+
],
|
|
82
|
+
"bumped_by": [
|
|
83
|
+
"generate-bdd",
|
|
84
|
+
"review-context"
|
|
85
|
+
],
|
|
86
|
+
"read_by": [
|
|
87
|
+
"generate-bdd",
|
|
88
|
+
"generate-code",
|
|
89
|
+
"generate-tech-docs",
|
|
90
|
+
"validate-traces",
|
|
91
|
+
"review-tech-docs",
|
|
92
|
+
"review-context"
|
|
93
|
+
],
|
|
94
|
+
"why": "Drift cấp file (Background/dataset/business-definition) mà sc_version không thấy."
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"name": "@trace.bdd_versions",
|
|
98
|
+
"artifact": "tech-design.md",
|
|
99
|
+
"scope": "file",
|
|
100
|
+
"shape": "map theo platform (system=1.5, web=1.9)",
|
|
101
|
+
"written_by": [
|
|
102
|
+
"generate-tech-docs",
|
|
103
|
+
"tech-design-template"
|
|
104
|
+
],
|
|
105
|
+
"read_by": [
|
|
106
|
+
"generate-code",
|
|
107
|
+
"validate-traces",
|
|
108
|
+
"review-tech-docs"
|
|
109
|
+
],
|
|
110
|
+
"why": "Số NHIỀU, cố ý khác @trace.bdd_version (scalar) — cùng tên cho hai kiểu dữ liệu làm vỡ parser generic."
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "@trace.platform",
|
|
114
|
+
"artifact": ".feature",
|
|
115
|
+
"scope": "file",
|
|
116
|
+
"required": "always",
|
|
117
|
+
"values_from": "platform",
|
|
118
|
+
"written_by": [
|
|
119
|
+
"generate-bdd",
|
|
120
|
+
"feature-template"
|
|
121
|
+
],
|
|
122
|
+
"read_by": [
|
|
123
|
+
"generate-code",
|
|
124
|
+
"generate-tech-docs",
|
|
125
|
+
"review-context",
|
|
126
|
+
"context-loader"
|
|
127
|
+
],
|
|
128
|
+
"why": "Quyết BE/FE ở generate-code (cấm fallback platform_type) + tên sổ trace + lookup design-spec. Lưu ý: validate-traces và report-bug KHÔNG đọc tag này — chúng suy platform từ TÊN FILE .tsv ({UC-ID}-{platform}.tsv), nên không phải consumer của tag."
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"name": "@trace.prd_version",
|
|
132
|
+
"artifact": ".feature + code",
|
|
133
|
+
"scope": "file + method",
|
|
134
|
+
"written_by": [
|
|
135
|
+
"generate-bdd",
|
|
136
|
+
"generate-code",
|
|
137
|
+
"feature-template"
|
|
138
|
+
],
|
|
139
|
+
"read_by": [
|
|
140
|
+
"generate-bdd",
|
|
141
|
+
"validate-traces",
|
|
142
|
+
"review-context"
|
|
143
|
+
],
|
|
144
|
+
"why": "Nguồn của PRD_DRIFT (validate-traces Step 4 so 3 tầng: PRD file, TSV, tag trong code)."
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"name": "@trace.implements",
|
|
148
|
+
"artifact": "code",
|
|
149
|
+
"scope": "method",
|
|
150
|
+
"shape": "{UC-ID}-SC{N}",
|
|
151
|
+
"written_by": [
|
|
152
|
+
"generate-code",
|
|
153
|
+
"setup-ai-first"
|
|
154
|
+
],
|
|
155
|
+
"read_by": [
|
|
156
|
+
"validate-traces",
|
|
157
|
+
"review-code",
|
|
158
|
+
"dev-gen-test",
|
|
159
|
+
"dev-smoke-test",
|
|
160
|
+
"fix-bug"
|
|
161
|
+
],
|
|
162
|
+
"why": "Khoá chính của trace ở tầng code. Tra bằng khớp chuỗi CHÍNH XÁC → cấm trỏ thư mục."
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"name": "@trace.source",
|
|
166
|
+
"artifact": "code",
|
|
167
|
+
"scope": "method",
|
|
168
|
+
"shape": "{specs_dir}/{domain}/{prd-slug}/bdd/{platform}/{UC-ID}-{slug}.feature",
|
|
169
|
+
"written_by": [
|
|
170
|
+
"generate-code",
|
|
171
|
+
"setup-ai-first"
|
|
172
|
+
],
|
|
173
|
+
"read_by": [
|
|
174
|
+
"review-code"
|
|
175
|
+
],
|
|
176
|
+
"why": "Con trỏ ngược về spec. PHẢI gồm segment {platform}."
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"name": "@trace.tech_doc_revision",
|
|
180
|
+
"artifact": "code",
|
|
181
|
+
"scope": "method",
|
|
182
|
+
"written_by": [
|
|
183
|
+
"generate-code"
|
|
184
|
+
],
|
|
185
|
+
"read_by": [
|
|
186
|
+
"review-code"
|
|
187
|
+
],
|
|
188
|
+
"why": "Ghi revision tech-doc mà method này được sinh theo. BẤT ĐỐI XỨNG ĐÃ BIẾT: validate-traces Step 5 tính TECHDOC_DRIFT từ cột TSV tech_doc_revision chứ không từ tag này (khác Step 4, có so tag @trace.prd_version trong code). Nên hiện chỉ review-code kiểm sự CÓ MẶT của nó. Muốn đối xứng thì Step 5 phải đọc thêm tag trong code."
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"name": "@trace.verifies",
|
|
192
|
+
"artifact": "test",
|
|
193
|
+
"scope": "method",
|
|
194
|
+
"shape": "{UC-ID}-SC{N}",
|
|
195
|
+
"written_by": [
|
|
196
|
+
"dev-gen-test",
|
|
197
|
+
"qc-run-test",
|
|
198
|
+
"fix-bug"
|
|
199
|
+
],
|
|
200
|
+
"read_by": [
|
|
201
|
+
"validate-traces",
|
|
202
|
+
"review-code",
|
|
203
|
+
"dev-run-test",
|
|
204
|
+
"qc-run-test"
|
|
205
|
+
],
|
|
206
|
+
"why": "Khớp test → sc_id khi ghi test_count/dev_selftest/qc_status."
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"name": "@trace.scenario",
|
|
210
|
+
"artifact": ".feature",
|
|
211
|
+
"scope": "scenario",
|
|
212
|
+
"shape": "{UC-ID}-SC{N}",
|
|
213
|
+
"written_by": [
|
|
214
|
+
"generate-bdd",
|
|
215
|
+
"propose-scenario",
|
|
216
|
+
"feature-template"
|
|
217
|
+
],
|
|
218
|
+
"read_by": [
|
|
219
|
+
"generate-bdd",
|
|
220
|
+
"review-context"
|
|
221
|
+
],
|
|
222
|
+
"why": "Sinh sc_id cho row TSV. Thiếu nó = scenario vô hình với toàn bộ coverage."
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"name": "@trace.status",
|
|
226
|
+
"artifact": ".feature + tech-design.md",
|
|
227
|
+
"scope": "file",
|
|
228
|
+
"values_from": "approval_status",
|
|
229
|
+
"written_by": [
|
|
230
|
+
"feature-template",
|
|
231
|
+
"review-context",
|
|
232
|
+
"review-tech-docs",
|
|
233
|
+
"generate-tech-docs",
|
|
234
|
+
"tech-design-template"
|
|
235
|
+
],
|
|
236
|
+
"read_by": [
|
|
237
|
+
"generate-code",
|
|
238
|
+
"validate-traces",
|
|
239
|
+
"review-tech-docs"
|
|
240
|
+
],
|
|
241
|
+
"why": "Cổng duyệt: DS1 của generate-code, và uc_status sync từ đây."
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"name": "@trace.revision",
|
|
245
|
+
"artifact": "tech-design.md",
|
|
246
|
+
"scope": "file",
|
|
247
|
+
"shape": "integer",
|
|
248
|
+
"written_by": [
|
|
249
|
+
"generate-tech-docs",
|
|
250
|
+
"review-tech-docs",
|
|
251
|
+
"tech-design-template"
|
|
252
|
+
],
|
|
253
|
+
"read_by": [
|
|
254
|
+
"generate-code",
|
|
255
|
+
"validate-traces"
|
|
256
|
+
],
|
|
257
|
+
"why": "Nguồn của tech_doc_revision + TECHDOC_DRIFT."
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"name": "@trace.api_source",
|
|
261
|
+
"artifact": ".feature + tech-design.md",
|
|
262
|
+
"scope": "file",
|
|
263
|
+
"written_by": [
|
|
264
|
+
"generate-bdd",
|
|
265
|
+
"tech-design-template"
|
|
266
|
+
],
|
|
267
|
+
"read_by": [
|
|
268
|
+
"review-tech-docs",
|
|
269
|
+
"review-context"
|
|
270
|
+
],
|
|
271
|
+
"why": "existing → bỏ cổng T7 + skip System BDD Synthesis S1-S3."
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"name": "@trace.stub",
|
|
275
|
+
"artifact": "code",
|
|
276
|
+
"scope": "method",
|
|
277
|
+
"written_by": [
|
|
278
|
+
"generate-code"
|
|
279
|
+
],
|
|
280
|
+
"read_by": [
|
|
281
|
+
"validate-traces",
|
|
282
|
+
"review-code"
|
|
283
|
+
],
|
|
284
|
+
"why": "Method trắng nội-feature. Nguồn của STUB_UNRESOLVED."
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"name": "@trace.mock_for",
|
|
288
|
+
"artifact": "code",
|
|
289
|
+
"scope": "class",
|
|
290
|
+
"written_by": [
|
|
291
|
+
"generate-code"
|
|
292
|
+
],
|
|
293
|
+
"read_by": [
|
|
294
|
+
"generate-code"
|
|
295
|
+
],
|
|
296
|
+
"why": "Đánh dấu layer mock của FE `--phase=ui` thuộc UC nào. `--phase=integration` dò lại chính tag này để biết mock nào phải thay bằng adapter thật — vừa ghi vừa đọc bởi cùng lệnh ở HAI phase khác nhau, đó là đúng."
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"name": "@trace.mock_source",
|
|
300
|
+
"artifact": "code",
|
|
301
|
+
"scope": "class",
|
|
302
|
+
"values": "contract | system-bdd",
|
|
303
|
+
"written_by": [
|
|
304
|
+
"generate-code"
|
|
305
|
+
],
|
|
306
|
+
"read_by": [
|
|
307
|
+
"generate-code"
|
|
308
|
+
],
|
|
309
|
+
"why": "Shape của mock suy từ đâu. `system-bdd` = infer từ behavior (KHÔNG phải full request/response shape) → phase integration phải dự kiến điều chỉnh; `contract` = lấy từ §4 tech-doc, khớp sẵn."
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
"name": "@trace.system_bdd",
|
|
313
|
+
"artifact": "code",
|
|
314
|
+
"scope": "class",
|
|
315
|
+
"written_by": [
|
|
316
|
+
"generate-code"
|
|
317
|
+
],
|
|
318
|
+
"read_by": [],
|
|
319
|
+
"allow_no_reader": "Con trỏ tới System BDD mà mock được dựng theo. Nhãn truy vết cho người đọc + reviewer; không có consumer tự động (phase integration route bằng @trace.mock_for/@trace.mock_source).",
|
|
320
|
+
"why": "Ghi mock này dựng theo file System BDD nào."
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"name": "@trace.be_contract",
|
|
324
|
+
"artifact": "code",
|
|
325
|
+
"scope": "class",
|
|
326
|
+
"written_by": [
|
|
327
|
+
"generate-code"
|
|
328
|
+
],
|
|
329
|
+
"read_by": [],
|
|
330
|
+
"allow_no_reader": "CHỈ có khi mock_source=contract — ghi tech-doc nào cấp shape. Nhãn truy vết, không có consumer tự động.",
|
|
331
|
+
"why": "Con trỏ tới tech-doc cấp shape cho mock."
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"name": "@trace.root_cause",
|
|
335
|
+
"artifact": "code",
|
|
336
|
+
"scope": "method",
|
|
337
|
+
"written_by": [
|
|
338
|
+
"fix-bug"
|
|
339
|
+
],
|
|
340
|
+
"read_by": [],
|
|
341
|
+
"allow_no_reader": "Nhãn cho người đọc code — mô tả ngắn nguyên nhân gốc của bug đã fix. Cùng nhóm với @trace.fixes.",
|
|
342
|
+
"why": "Ghi lại nguyên nhân gốc tại chỗ sửa."
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"name": "@trace.regression",
|
|
346
|
+
"artifact": "test",
|
|
347
|
+
"scope": "method",
|
|
348
|
+
"written_by": [
|
|
349
|
+
"fix-bug"
|
|
350
|
+
],
|
|
351
|
+
"read_by": [],
|
|
352
|
+
"allow_no_reader": "Đánh dấu test hồi quy sinh kèm bản fix. Nhãn cho người đọc; test_count/test_classes trong TSV mới là đường máy đọc (G7).",
|
|
353
|
+
"why": "Nhận diện test hồi quy của một ticket."
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"name": "@trace.title",
|
|
357
|
+
"artifact": ".feature",
|
|
358
|
+
"scope": "file",
|
|
359
|
+
"written_by": [
|
|
360
|
+
"feature-template"
|
|
361
|
+
],
|
|
362
|
+
"read_by": [
|
|
363
|
+
"review-context"
|
|
364
|
+
],
|
|
365
|
+
"why": "Tên feature dạng người đọc. review-context B5 Nhóm B chỉ kiểm CÓ MẶT, không kiểm giá trị."
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"name": "@trace.author",
|
|
369
|
+
"artifact": ".feature",
|
|
370
|
+
"scope": "file",
|
|
371
|
+
"written_by": [
|
|
372
|
+
"feature-template"
|
|
373
|
+
],
|
|
374
|
+
"read_by": [
|
|
375
|
+
"review-context"
|
|
376
|
+
],
|
|
377
|
+
"why": "Nguồn gốc file (`AI-generated`). Chỉ kiểm có mặt — xem @trace.title."
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"name": "@trace.created_at",
|
|
381
|
+
"artifact": ".feature",
|
|
382
|
+
"scope": "file",
|
|
383
|
+
"written_by": [
|
|
384
|
+
"feature-template"
|
|
385
|
+
],
|
|
386
|
+
"read_by": [
|
|
387
|
+
"review-context"
|
|
388
|
+
],
|
|
389
|
+
"why": "Ngày tạo file. Chỉ kiểm có mặt — xem @trace.title. KHÁC last_updated của TSV (cái đó là trạng thái, cái này là gốc)."
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"name": "@trace.generated_at",
|
|
393
|
+
"artifact": "tech-design.md",
|
|
394
|
+
"scope": "file",
|
|
395
|
+
"written_by": [
|
|
396
|
+
"tech-design-template"
|
|
397
|
+
],
|
|
398
|
+
"read_by": [],
|
|
399
|
+
"allow_no_reader": "Ngày sinh tech-doc. Drift của tech-doc đo bằng @trace.revision (integer), KHÔNG bằng ngày — nên field này thuần thông tin cho người đọc.",
|
|
400
|
+
"why": "Ngày sinh tech-doc, dạng người đọc."
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
"name": "@trace.business_rules",
|
|
404
|
+
"artifact": ".feature",
|
|
405
|
+
"scope": "scenario",
|
|
406
|
+
"shape": "{TICKET-ID}-UC{N}-BR{m}, …",
|
|
407
|
+
"written_by": [
|
|
408
|
+
"generate-bdd",
|
|
409
|
+
"feature-template",
|
|
410
|
+
"propose-scenario"
|
|
411
|
+
],
|
|
412
|
+
"read_by": [
|
|
413
|
+
"review-context"
|
|
414
|
+
],
|
|
415
|
+
"$reader_note": "generate-tech-docs đọc BR ID từ THÂN scenario (`BR{m}`), không đọc tag này — nên nó không phải consumer.",
|
|
416
|
+
"why": "Link scenario ↔ Business Rule của PRD. BR đánh số LIÊN TỤC toàn PRD (không reset theo UC — G14), nên ID ở đây phải lấy NGUYÊN từ PRD §3. Mở cột bảng BR trên PRD đã có BDD sẽ làm churn ID và phá link này."
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"name": "@trace.dataset",
|
|
420
|
+
"artifact": ".feature",
|
|
421
|
+
"scope": "file",
|
|
422
|
+
"$producer_note": "CHỈ feature-template — nó được {{include}} nướng cứng vào generate-bdd lúc build, nên generate-bdd không nhắc tên field này ở prose của chính nó. Khai thêm generate-bdd sẽ làm R3 fail.",
|
|
423
|
+
"written_by": [
|
|
424
|
+
"feature-template"
|
|
425
|
+
],
|
|
426
|
+
"read_by": [
|
|
427
|
+
"review-context",
|
|
428
|
+
"validate-traces"
|
|
429
|
+
],
|
|
430
|
+
"why": "File testdata dùng chung của feature. Đổi nó là thay đổi CẤP FILE mà sc_version không thấy — chính vì vậy Step 5c liệt nó vào nguồn của BDD_DRIFT."
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
"name": "@trace.prd",
|
|
434
|
+
"artifact": ".feature",
|
|
435
|
+
"scope": "file",
|
|
436
|
+
"shape": "{TICKET-ID}",
|
|
437
|
+
"$producer_note": "CHỈ feature-template — xem @trace.dataset.",
|
|
438
|
+
"written_by": [
|
|
439
|
+
"feature-template"
|
|
440
|
+
],
|
|
441
|
+
"read_by": [
|
|
442
|
+
"review-context"
|
|
443
|
+
],
|
|
444
|
+
"why": "Con trỏ ngược .feature → PRD. Mang TICKET-ID chứ không phải path, vì tech-doc và trace cũng khoá theo TICKET-ID."
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"name": "@trace.platforms",
|
|
448
|
+
"artifact": "tech-design.md",
|
|
449
|
+
"scope": "file",
|
|
450
|
+
"shape": "danh sách platform",
|
|
451
|
+
"written_by": [
|
|
452
|
+
"generate-tech-docs",
|
|
453
|
+
"tech-design-template"
|
|
454
|
+
],
|
|
455
|
+
"read_by": [
|
|
456
|
+
"review-tech-docs"
|
|
457
|
+
],
|
|
458
|
+
"why": "Số NHIỀU, cố ý khác @trace.platform (scalar, ở .feature) — cùng lý do như bdd_version vs bdd_versions (G15): tech-doc là doc GỘP phủ nhiều platform."
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
"name": "@trace.test_type",
|
|
462
|
+
"artifact": "test",
|
|
463
|
+
"scope": "method",
|
|
464
|
+
"written_by": [
|
|
465
|
+
"dev-gen-test"
|
|
466
|
+
],
|
|
467
|
+
"read_by": [],
|
|
468
|
+
"allow_no_reader": "NHÃN CHẾT — phát hiện khi khai schema (G30 lô 3). /dev-gen-test dán nó lên mọi test class nhưng KHÔNG lệnh nào đọc: dev-run-test chạy theo test_command của project, qc-* dùng stack riêng. Giữ vì nó là nhãn hữu ích cho người đọc code và là chỗ móc sẵn nếu sau này muốn chạy test theo loại (vd chỉ chạy unit ở pre-commit). Nếu 6 tháng nữa vẫn không consumer nào → bỏ hẳn thay vì để nợ.",
|
|
469
|
+
"why": "Phân loại test (unit/integration/e2e…). Hiện chỉ là nhãn cho người đọc."
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
"name": "@trace.testid_attr",
|
|
473
|
+
"artifact": "tech-design.md",
|
|
474
|
+
"scope": "file",
|
|
475
|
+
"written_by": [
|
|
476
|
+
"map-testids"
|
|
477
|
+
],
|
|
478
|
+
"read_by": [
|
|
479
|
+
"generate-code",
|
|
480
|
+
"qc-run-test",
|
|
481
|
+
"qc-design-test"
|
|
482
|
+
],
|
|
483
|
+
"$history_note": "G30 lô 3 phát hiện field này TỰ MÔ TẢ là contract FE↔QC nhưng chỉ nửa FE (generate-code) đọc — QC tự suy tên thuộc tính từ platform. G37 nối nửa QC: qc-run-test đọc để CẤU HÌNH test-id attribute (Playwright get_by_test_id mặc định dò `data-testid`; dự án dùng `data-test`/`data-qa` sẽ trượt 100% locator nếu không set), qc-design-test ghi lại vào metadata .Test.md để reviewer đối chiếu.",
|
|
484
|
+
"why": "Tên thuộc tính test-id của stack — contract FE↔QC. FE emit theo nó (generate-code), QC cấu hình locator theo nó (qc-run-test). Suy từ platform thay vì đọc field = phát biểu lại sự thật đã ghi ở nơi khác, và hỏng IM LẶNG: test fail 'element not found' trông y hệt bug sản phẩm."
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
"name": "@trace.domain",
|
|
488
|
+
"artifact": ".feature + tech-design.md",
|
|
489
|
+
"scope": "file",
|
|
490
|
+
"written_by": [
|
|
491
|
+
"generate-bdd",
|
|
492
|
+
"feature-template",
|
|
493
|
+
"tech-design-template"
|
|
494
|
+
],
|
|
495
|
+
"read_by": [
|
|
496
|
+
"context-loader",
|
|
497
|
+
"review-context",
|
|
498
|
+
"review-tech-docs",
|
|
499
|
+
"generate-spec-manifest",
|
|
500
|
+
"setup-ai-first"
|
|
501
|
+
],
|
|
502
|
+
"why": "Khoá ĐỊNH TUYẾN. context-loader Bước 1.5 đọc nó từ frontmatter target để chọn service submodule — sai là ghi code/trace nhầm repo mà không báo gì."
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
"name": "@trace.id",
|
|
506
|
+
"artifact": ".feature + tech-design.md",
|
|
507
|
+
"scope": "file",
|
|
508
|
+
"shape": "{TICKET-ID}-UC{N}",
|
|
509
|
+
"written_by": [
|
|
510
|
+
"feature-template",
|
|
511
|
+
"tech-design-template"
|
|
512
|
+
],
|
|
513
|
+
"read_by": [
|
|
514
|
+
"generate-code",
|
|
515
|
+
"generate-tech-docs",
|
|
516
|
+
"qc-analyze",
|
|
517
|
+
"review-context"
|
|
518
|
+
],
|
|
519
|
+
"why": "UC-ID của file. generate-code đọc nó để chốt Scope Lock (implement ĐÚNG UC này, không lan sang .feature khác)."
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
"name": "@trace.module",
|
|
523
|
+
"artifact": ".feature + tech-design.md",
|
|
524
|
+
"scope": "file",
|
|
525
|
+
"written_by": [
|
|
526
|
+
"feature-template",
|
|
527
|
+
"tech-design-template"
|
|
528
|
+
],
|
|
529
|
+
"read_by": [
|
|
530
|
+
"dev-gen-test",
|
|
531
|
+
"generate-tech-docs",
|
|
532
|
+
"review-context"
|
|
533
|
+
],
|
|
534
|
+
"why": "Stack module của service sở hữu. dev-gen-test dùng để chọn test pattern. Giá trị `unknown` ở spec repo mode là HỢP LỆ — review-context không được flag."
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
"name": "@trace.ucs",
|
|
538
|
+
"artifact": "tech-design.md",
|
|
539
|
+
"scope": "file",
|
|
540
|
+
"shape": "danh sách UC-ID",
|
|
541
|
+
"written_by": [
|
|
542
|
+
"generate-tech-docs",
|
|
543
|
+
"tech-design-template"
|
|
544
|
+
],
|
|
545
|
+
"read_by": [
|
|
546
|
+
"review-tech-docs",
|
|
547
|
+
"gate"
|
|
548
|
+
],
|
|
549
|
+
"why": "Tech-doc là doc GỘP cấp PRD — đây là danh sách UC nó phủ. Cần vì tên file mang {TICKET-ID} chứ không mang {UC-ID} (G10): gate phải tách TICKET-ID rồi glob, và dùng field này để biết doc có phủ UC đang hỏi không."
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
"name": "@trace.seam_port",
|
|
553
|
+
"artifact": "code",
|
|
554
|
+
"scope": "class",
|
|
555
|
+
"written_by": [
|
|
556
|
+
"generate-code"
|
|
557
|
+
],
|
|
558
|
+
"read_by": [
|
|
559
|
+
"review-code"
|
|
560
|
+
],
|
|
561
|
+
"why": "Tên port mà class stub đang giả lập. Đi CẶP với @trace.seam_pending — review-code kiểm cả hai phải có mặt cùng dòng `PENDING` trong _seams.tsv. validate-traces Step 5b nhận diện seam qua @trace.seam_pending + cột `name` của sổ, KHÔNG đọc tag này."
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
"name": "@trace.stub_owner",
|
|
565
|
+
"artifact": "code",
|
|
566
|
+
"scope": "method",
|
|
567
|
+
"written_by": [
|
|
568
|
+
"generate-code"
|
|
569
|
+
],
|
|
570
|
+
"read_by": [
|
|
571
|
+
"validate-traces",
|
|
572
|
+
"review-code"
|
|
573
|
+
],
|
|
574
|
+
"why": "UC lẽ ra phải lấp method trắng này. Step 5b hỏi 'owner đã gen chưa' để quyết STUB_PENDING (ⓘ) vs STUB_UNRESOLVED (🔴 chặn PR). Mất tag = mất luôn phép phân biệt đó → hoặc báo động oan mọi stub, hoặc bỏ sót hàm trắng mồ côi."
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
"name": "@trace.stub_for",
|
|
578
|
+
"artifact": "code",
|
|
579
|
+
"scope": "method",
|
|
580
|
+
"written_by": [
|
|
581
|
+
"generate-code"
|
|
582
|
+
],
|
|
583
|
+
"read_by": [
|
|
584
|
+
"validate-traces",
|
|
585
|
+
"review-code"
|
|
586
|
+
],
|
|
587
|
+
"why": "Trách nhiệm mà method trắng này đang giữ chỗ. Step 5b dùng nó để dò 'có hàm THẬT song song cùng trách nhiệm không' — dấu hiệu Fill-before-create đã trượt (BDD owner đẻ hàm mới thay vì lấp hàm cũ)."
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
"name": "@trace.sign_off",
|
|
591
|
+
"artifact": "tech-design.md",
|
|
592
|
+
"scope": "file",
|
|
593
|
+
"written_by": [
|
|
594
|
+
"review-tech-docs"
|
|
595
|
+
],
|
|
596
|
+
"read_by": [
|
|
597
|
+
"review-tech-docs"
|
|
598
|
+
],
|
|
599
|
+
"why": "Cổng T7 — xác nhận cross-team của tech-doc system BDD. Vừa ghi vừa đọc bởi cùng một lệnh là ĐÚNG (nó là sổ trạng thái nội bộ của cổng đó, không phải contract liên lệnh). LƯU Ý: tech-design.template.md KHÔNG phát ra field này — review-tech-docs tự thêm khi thiếu, nên template không phải producer."
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
"name": "@trace.seam_pending",
|
|
603
|
+
"artifact": "code",
|
|
604
|
+
"scope": "class",
|
|
605
|
+
"written_by": [
|
|
606
|
+
"generate-code"
|
|
607
|
+
],
|
|
608
|
+
"read_by": [
|
|
609
|
+
"validate-traces",
|
|
610
|
+
"review-code"
|
|
611
|
+
],
|
|
612
|
+
"why": "Port cross-UC chưa có hàng thật. Nguồn của SEAM_UNWIRED."
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
"name": "@trace.service",
|
|
616
|
+
"artifact": ".feature",
|
|
617
|
+
"scope": "file",
|
|
618
|
+
"written_by": [
|
|
619
|
+
"generate-bdd",
|
|
620
|
+
"feature-template"
|
|
621
|
+
],
|
|
622
|
+
"read_by": [
|
|
623
|
+
"generate-bdd",
|
|
624
|
+
"dev-gen-test",
|
|
625
|
+
"generate-tech-docs",
|
|
626
|
+
"review-context"
|
|
627
|
+
],
|
|
628
|
+
"why": "Nguồn DUY NHẤT của cột TSV `service` (cột 23) — trace gộp không tách theo service nên thiếu tag này là mất hẳn thông tin sở hữu ở cấp row. BẮT BUỘC mọi mode từ v0.4.3 (trước đó feature.template chủ động bỏ ở spec repo mode, và review-context xếp nó vào Nhóm C có-điều-kiện)."
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
"name": "@trace.design_spec_version",
|
|
632
|
+
"artifact": "code",
|
|
633
|
+
"scope": "method",
|
|
634
|
+
"written_by": [
|
|
635
|
+
"generate-code"
|
|
636
|
+
],
|
|
637
|
+
"read_by": [
|
|
638
|
+
"validate-traces",
|
|
639
|
+
"review-code"
|
|
640
|
+
],
|
|
641
|
+
"why": "Nguồn của DESIGNSPEC_DRIFT (Step 5d). CHỈ FE/App — bỏ hẳn dòng tag với system/backend."
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
"name": "@trace.fixes",
|
|
645
|
+
"artifact": "code",
|
|
646
|
+
"scope": "method",
|
|
647
|
+
"written_by": [
|
|
648
|
+
"fix-bug"
|
|
649
|
+
],
|
|
650
|
+
"read_by": [],
|
|
651
|
+
"allow_no_reader": "Nhãn cho người đọc code, không có consumer tự động."
|
|
652
|
+
}
|
|
653
|
+
],
|
|
654
|
+
"tsv_columns": [
|
|
655
|
+
{
|
|
656
|
+
"n": 1,
|
|
657
|
+
"name": "sc_id",
|
|
658
|
+
"written_by": [
|
|
659
|
+
"generate-bdd"
|
|
660
|
+
],
|
|
661
|
+
"read_by": [
|
|
662
|
+
"validate-traces",
|
|
663
|
+
"generate-code",
|
|
664
|
+
"dev-gen-test",
|
|
665
|
+
"dev-run-test",
|
|
666
|
+
"qc-run-test",
|
|
667
|
+
"report-bug",
|
|
668
|
+
"fix-bug"
|
|
669
|
+
]
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
"n": 2,
|
|
673
|
+
"name": "sc_title",
|
|
674
|
+
"written_by": [
|
|
675
|
+
"generate-bdd"
|
|
676
|
+
],
|
|
677
|
+
"read_by": [
|
|
678
|
+
"validate-traces"
|
|
679
|
+
]
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
"n": 3,
|
|
683
|
+
"name": "spec_ver",
|
|
684
|
+
"written_by": [
|
|
685
|
+
"generate-bdd",
|
|
686
|
+
"validate-traces",
|
|
687
|
+
"review-context"
|
|
688
|
+
],
|
|
689
|
+
"read_by": [
|
|
690
|
+
"validate-traces",
|
|
691
|
+
"generate-code"
|
|
692
|
+
]
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
"n": 4,
|
|
696
|
+
"name": "gen_ver",
|
|
697
|
+
"written_by": [
|
|
698
|
+
"generate-code",
|
|
699
|
+
"validate-traces"
|
|
700
|
+
],
|
|
701
|
+
"read_by": [
|
|
702
|
+
"validate-traces",
|
|
703
|
+
"generate-bdd"
|
|
704
|
+
]
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
"n": 5,
|
|
708
|
+
"name": "implemented_by",
|
|
709
|
+
"written_by": [
|
|
710
|
+
"generate-code",
|
|
711
|
+
"validate-traces"
|
|
712
|
+
],
|
|
713
|
+
"read_by": [
|
|
714
|
+
"validate-traces",
|
|
715
|
+
"generate-bdd"
|
|
716
|
+
]
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
"n": 6,
|
|
720
|
+
"name": "test_count",
|
|
721
|
+
"written_by": [
|
|
722
|
+
"dev-gen-test",
|
|
723
|
+
"fix-bug"
|
|
724
|
+
],
|
|
725
|
+
"read_by": [
|
|
726
|
+
"validate-traces",
|
|
727
|
+
"generate-bdd"
|
|
728
|
+
]
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
"n": 7,
|
|
732
|
+
"name": "test_classes",
|
|
733
|
+
"written_by": [
|
|
734
|
+
"dev-gen-test",
|
|
735
|
+
"fix-bug"
|
|
736
|
+
],
|
|
737
|
+
"read_by": [
|
|
738
|
+
"validate-traces",
|
|
739
|
+
"generate-bdd"
|
|
740
|
+
]
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
"n": 8,
|
|
744
|
+
"name": "dev_selftest",
|
|
745
|
+
"$invalidated_by_comment": [
|
|
746
|
+
"PRODUCER vs INVALIDATOR — hai vai khác nhau, cùng nằm trong written_by.",
|
|
747
|
+
"Chủ sở hữu (ghi giá trị KHẲNG ĐỊNH pass/fail): dev-run-test.",
|
|
748
|
+
"Invalidator (chỉ được hạ về not_run/— khi giá trị cũ HẾT ĐÚNG): generate-bdd (spec đổi),",
|
|
749
|
+
"generate-code (lấp stub hoặc sửa method do DRIFT), fix-bug (code đổi), dev-gen-test (test mới).",
|
|
750
|
+
"Luật đầy đủ: rules/workflow.md §Trace Contract — 'Làm mất hiệu lực ≠ ghi đè'.",
|
|
751
|
+
"Vì sao cần: giữ một 'pass' sinh ra từ spec đã bị sửa là BÁO CÁO SAI. Trước G28 chỉ",
|
|
752
|
+
"nhánh lấp-stub hạ cờ, nên chuỗi spec-đổi → DRIFT → regen → OK kết thúc bằng dashboard",
|
|
753
|
+
"xanh hoàn toàn trên một hành vi chưa từng được test."
|
|
754
|
+
],
|
|
755
|
+
"written_by": [
|
|
756
|
+
"dev-run-test",
|
|
757
|
+
"dev-gen-test",
|
|
758
|
+
"generate-code",
|
|
759
|
+
"generate-bdd",
|
|
760
|
+
"fix-bug"
|
|
761
|
+
],
|
|
762
|
+
"read_by": [
|
|
763
|
+
"validate-traces",
|
|
764
|
+
"qc-run-test"
|
|
765
|
+
]
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
"n": 9,
|
|
769
|
+
"name": "dev_selftest_at",
|
|
770
|
+
"$comment": "Chủ: dev-run-test. Invalidator (hạ về —): generate-bdd · generate-code · fix-bug. Xem dev_selftest.",
|
|
771
|
+
"written_by": [
|
|
772
|
+
"dev-run-test",
|
|
773
|
+
"generate-code",
|
|
774
|
+
"generate-bdd",
|
|
775
|
+
"fix-bug"
|
|
776
|
+
],
|
|
777
|
+
"read_by": [
|
|
778
|
+
"validate-traces",
|
|
779
|
+
"qc-run-test"
|
|
780
|
+
]
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
"n": 10,
|
|
784
|
+
"name": "qc_status",
|
|
785
|
+
"$comment": "Chủ (ghi pass/fail/skip): qc-run-test — DUY NHẤT. Invalidator (chỉ hạ về not_run khi spec/code/HỢP ĐỒNG TEST-ID vừa đổi): generate-bdd · generate-code · map-testids. Xem dev_selftest + rules/workflow.md 'Làm mất hiệu lực ≠ ghi đè'. map-testids vào danh sách này vì đổi một test-id trong §4.5.6 làm script QC bám id cũ HẾT ĐÚNG: nó định vị một element không còn mang id đó, nên `pass` cũ không còn nghĩa 'scenario đã được nghiệm thu theo spec hiện tại'. Cột 'Serves SC' của row chính là chỉ mục ngược để biết SC nào bị ảnh hưởng.",
|
|
786
|
+
"written_by": [
|
|
787
|
+
"qc-run-test",
|
|
788
|
+
"generate-bdd",
|
|
789
|
+
"generate-code",
|
|
790
|
+
"map-testids"
|
|
791
|
+
],
|
|
792
|
+
"read_by": [
|
|
793
|
+
"validate-traces",
|
|
794
|
+
"dev-run-test",
|
|
795
|
+
"generate-code",
|
|
796
|
+
"report-bug",
|
|
797
|
+
"fix-bug"
|
|
798
|
+
]
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
"n": 11,
|
|
802
|
+
"name": "qc_run_at",
|
|
803
|
+
"$comment": "Chủ: qc-run-test. Invalidator (hạ về —): generate-bdd · generate-code · map-testids. Xem qc_status.",
|
|
804
|
+
"written_by": [
|
|
805
|
+
"qc-run-test",
|
|
806
|
+
"generate-bdd",
|
|
807
|
+
"generate-code",
|
|
808
|
+
"map-testids"
|
|
809
|
+
],
|
|
810
|
+
"read_by": [
|
|
811
|
+
"validate-traces",
|
|
812
|
+
"dev-run-test",
|
|
813
|
+
"generate-code"
|
|
814
|
+
]
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
"n": 12,
|
|
818
|
+
"name": "qc_owner",
|
|
819
|
+
"written_by": [
|
|
820
|
+
"qc-run-test",
|
|
821
|
+
"report-bug"
|
|
822
|
+
],
|
|
823
|
+
"read_by": [
|
|
824
|
+
"validate-traces",
|
|
825
|
+
"generate-code",
|
|
826
|
+
"fix-bug"
|
|
827
|
+
]
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
"n": 13,
|
|
831
|
+
"name": "qc_blocked_by",
|
|
832
|
+
"written_by": [
|
|
833
|
+
"qc-run-test",
|
|
834
|
+
"report-bug"
|
|
835
|
+
],
|
|
836
|
+
"read_by": [
|
|
837
|
+
"validate-traces",
|
|
838
|
+
"generate-code",
|
|
839
|
+
"qc-run-test"
|
|
840
|
+
]
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
"n": 14,
|
|
844
|
+
"name": "prd_version",
|
|
845
|
+
"written_by": [
|
|
846
|
+
"generate-bdd"
|
|
847
|
+
],
|
|
848
|
+
"read_by": [
|
|
849
|
+
"validate-traces",
|
|
850
|
+
"generate-code"
|
|
851
|
+
]
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
"n": 15,
|
|
855
|
+
"name": "bdd_version",
|
|
856
|
+
"written_by": [
|
|
857
|
+
"generate-bdd",
|
|
858
|
+
"review-context"
|
|
859
|
+
],
|
|
860
|
+
"read_by": [
|
|
861
|
+
"validate-traces"
|
|
862
|
+
]
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
"n": 16,
|
|
866
|
+
"name": "tech_doc_revision",
|
|
867
|
+
"$comment": [
|
|
868
|
+
"Chủ: review-tech-docs (set về @trace.revision mới khi duyệt) + generate-code.",
|
|
869
|
+
"BUMPER thứ ba: map-testids — CHỈ khi Step 5b làm ĐỔI giá trị một test-id ĐÃ CÓ trong §4.5.6.",
|
|
870
|
+
"",
|
|
871
|
+
"VÌ SAO (G64): §4.5.6 là hợp đồng mà /qc-design-test CHÉP CỨNG giá trị id vào .Test.md —",
|
|
872
|
+
"artifact bền, nằm lại. G63 dựng cơ chế phát hiện theo NHÃN: .Test.md stamp tech_doc_revision,",
|
|
873
|
+
"trạm 4-5 so với hiện tại. Nhưng map-testids sửa §4.5.6 mà KHÔNG bump nhãn ⇒ stamp KHÔNG NỔ",
|
|
874
|
+
"đúng ca quan trọng nhất — và đó là 'điểm mù tuyệt đối' rules/workflow.md đã nêu: 'mọi drift",
|
|
875
|
+
"detector so NHÃN VERSION, không so NỘI DUNG'.",
|
|
876
|
+
"",
|
|
877
|
+
"Đường vòng cũ — Next của map-testids là /review-tech-docs, lệnh đó CÓ bump — chỉ đúng KHI",
|
|
878
|
+
"người dùng đi theo Next. Mà Step 5b tồn tại chính vì ca 'sửa nhanh một id rồi đi tiếp'.",
|
|
879
|
+
"Dựa vào Next là dựa vào kỷ luật, không phải vào máy.",
|
|
880
|
+
"",
|
|
881
|
+
"THÊM ROW MỚI KHÔNG BUMP: chưa có .Test.md nào bám id mới nên không gì hết đúng. Cùng điều",
|
|
882
|
+
"kiện với việc Step 5b hạ qc_status."
|
|
883
|
+
],
|
|
884
|
+
"written_by": [
|
|
885
|
+
"generate-code",
|
|
886
|
+
"review-tech-docs",
|
|
887
|
+
"map-testids"
|
|
888
|
+
],
|
|
889
|
+
"read_by": [
|
|
890
|
+
"validate-traces",
|
|
891
|
+
"generate-bdd"
|
|
892
|
+
]
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
"n": 17,
|
|
896
|
+
"name": "fe_tech_doc_revision",
|
|
897
|
+
"written_by": [
|
|
898
|
+
"generate-code"
|
|
899
|
+
],
|
|
900
|
+
"read_by": [
|
|
901
|
+
"validate-traces",
|
|
902
|
+
"generate-bdd",
|
|
903
|
+
"review-tech-docs"
|
|
904
|
+
]
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
"n": 18,
|
|
908
|
+
"name": "prd_status",
|
|
909
|
+
"written_by": [
|
|
910
|
+
"generate-bdd",
|
|
911
|
+
"validate-traces"
|
|
912
|
+
],
|
|
913
|
+
"read_by": [
|
|
914
|
+
"validate-traces"
|
|
915
|
+
]
|
|
916
|
+
},
|
|
917
|
+
{
|
|
918
|
+
"n": 19,
|
|
919
|
+
"name": "uc_status",
|
|
920
|
+
"written_by": [
|
|
921
|
+
"generate-bdd",
|
|
922
|
+
"validate-traces",
|
|
923
|
+
"review-context"
|
|
924
|
+
],
|
|
925
|
+
"read_by": [
|
|
926
|
+
"validate-traces",
|
|
927
|
+
"generate-code"
|
|
928
|
+
]
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
"n": 20,
|
|
932
|
+
"name": "fe_phase",
|
|
933
|
+
"written_by": [
|
|
934
|
+
"generate-code",
|
|
935
|
+
"generate-bdd",
|
|
936
|
+
"validate-traces"
|
|
937
|
+
],
|
|
938
|
+
"read_by": [
|
|
939
|
+
"validate-traces"
|
|
940
|
+
]
|
|
941
|
+
},
|
|
942
|
+
{
|
|
943
|
+
"n": 21,
|
|
944
|
+
"name": "status",
|
|
945
|
+
"written_by": [
|
|
946
|
+
"validate-traces",
|
|
947
|
+
"generate-bdd"
|
|
948
|
+
],
|
|
949
|
+
"read_by": [
|
|
950
|
+
"validate-traces",
|
|
951
|
+
"generate-code",
|
|
952
|
+
"dev-run-test",
|
|
953
|
+
"qc-run-test"
|
|
954
|
+
]
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
"n": 23,
|
|
958
|
+
"name": "service",
|
|
959
|
+
"$comment": [
|
|
960
|
+
"Đội/submodule sở hữu scenario. Nguồn: @trace.service của header .feature.",
|
|
961
|
+
"VÌ SAO TỒN TẠI (G31): validate-traces Step 0 và trace-mirror.md đều khẳng định trace gộp",
|
|
962
|
+
"'không cần tách theo service vì mỗi row mang @trace.service' — nhưng TSV KHÔNG có cột nào",
|
|
963
|
+
"cho nó và JSON report cũng không. Cột này làm lời khẳng định kia thành sự thật.",
|
|
964
|
+
"",
|
|
965
|
+
"BỐN GIÁ TRỊ — G51 tách hai cái từng bị gộp:",
|
|
966
|
+
" {path} = đã route xong, đây là repo sở hữu",
|
|
967
|
+
" unrouted = CHƯA AI QUYẾT repo. Trạng thái HỢP LỆ và BÌNH THƯỜNG ở feature đầu tiên của",
|
|
968
|
+
" một domain mới. Cờ 🟠 SERVICE_UNROUTED. KHÔNG chặn BDD, KHÔNG chặn PR.",
|
|
969
|
+
" unresolved = CONFIG SAI CẤU TRÚC (một entry vừa có path vừa có by_prd_slug, hoặc",
|
|
970
|
+
" by_prd_slug lồng nhau). Đây là BUG cần sửa file, không phải trạng thái chờ.",
|
|
971
|
+
" '—' = single-service mode, không có khái niệm service",
|
|
972
|
+
"",
|
|
973
|
+
"VÌ SAO PHẢI TÁCH (G51): trước đó 'unresolved' mang CẢ HAI nghĩa nên cả hai chịu chung một",
|
|
974
|
+
"hình phạt — /generate-bdd DỪNG HẲN. Nhưng PRD/BDD là artifact NGHIỆP VỤ: PO biết domain",
|
|
975
|
+
"(auth, payment) và biết platform (web/app — người dùng làm việc đó ở đâu), nhưng KHÔNG biết",
|
|
976
|
+
"code sẽ nằm repo nào, và thường lúc đó CHƯA AI QUYẾT. Nên cổng đặt sai phase: nó chặn phase",
|
|
977
|
+
"KHÔNG CẦN biết, còn generate-code — phase BUỘC PHẢI biết mới ghi được file — thì không kiểm.",
|
|
978
|
+
"Ca bị đánh nặng nhất là feature ĐẦU TIÊN của một domain mới: chưa có mapping ⇒ PO bị chặn",
|
|
979
|
+
"bởi một quyết định thuộc architect, ở phase architect còn chưa vào.",
|
|
980
|
+
"",
|
|
981
|
+
"AI PHÂN GIẢI: validate-traces đọc lại services: mỗi lần chạy và nâng unrouted → path khi",
|
|
982
|
+
"mapping xuất hiện — giống cách nó đã làm với spec_ver. Architect thêm mapping ⇒ sổ TỰ LÀNH,",
|
|
983
|
+
"không sửa tay, KHÔNG phải chạy lại /generate-bdd. Vì thế validate-traces là producer thứ hai",
|
|
984
|
+
"của cột này, và đó là ngoại lệ CÓ CHỦ Ý với luật 'mỗi cột một chủ': nó không ghi giá trị mới,",
|
|
985
|
+
"nó chỉ phân giải một placeholder mà generate-bdd đã cố ý để lại."
|
|
986
|
+
],
|
|
987
|
+
"written_by": [
|
|
988
|
+
"generate-bdd",
|
|
989
|
+
"validate-traces"
|
|
990
|
+
],
|
|
991
|
+
"read_by": [
|
|
992
|
+
"validate-traces",
|
|
993
|
+
"generate-code"
|
|
994
|
+
]
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
"n": 24,
|
|
998
|
+
"name": "design_spec_version",
|
|
999
|
+
"$comment": [
|
|
1000
|
+
"Version design-spec tại thời điểm sinh BDD. Nguồn: | **Version** | của design-spec.",
|
|
1001
|
+
"VÌ SAO TỒN TẠI (G32): design-spec điều khiển CẢ BDD FE/App (Screen States + AC-UI) LẪN code",
|
|
1002
|
+
"FE (màn hình, component inventory, Figma frame) — nhưng là artifact upstream DUY NHẤT không",
|
|
1003
|
+
"có cột TSV, không có tag trong code, không có cờ drift. Nó tự bảo vệ một chiều (reset draft",
|
|
1004
|
+
"khi PRD đổi), còn chiều 'designer sửa design-spec SAU KHI BDD/code đã sinh' thì không gì bắt.",
|
|
1005
|
+
"GAPS.md G2 mở đầu bằng 'tầng BDD là tầng DUY NHẤT không có cờ drift' — câu đó đúng lúc viết,",
|
|
1006
|
+
"vì bảng kiểm kê chỉ tính PRD/BDD/tech-doc/code. Design-spec không nằm trong bảng nên không ai đếm.",
|
|
1007
|
+
"'—' cho system/backend và khi sinh BDD mà không có design-spec."
|
|
1008
|
+
],
|
|
1009
|
+
"written_by": [
|
|
1010
|
+
"generate-bdd"
|
|
1011
|
+
],
|
|
1012
|
+
"read_by": [
|
|
1013
|
+
"validate-traces"
|
|
1014
|
+
]
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
"n": 22,
|
|
1018
|
+
"name": "last_updated",
|
|
1019
|
+
"written_by": [
|
|
1020
|
+
"generate-bdd",
|
|
1021
|
+
"generate-code",
|
|
1022
|
+
"dev-gen-test",
|
|
1023
|
+
"dev-run-test",
|
|
1024
|
+
"qc-run-test",
|
|
1025
|
+
"review-context",
|
|
1026
|
+
"review-tech-docs",
|
|
1027
|
+
"fix-bug"
|
|
1028
|
+
],
|
|
1029
|
+
"read_by": [
|
|
1030
|
+
"validate-traces"
|
|
1031
|
+
]
|
|
1032
|
+
}
|
|
1033
|
+
],
|
|
1034
|
+
"aux_tables": [
|
|
1035
|
+
{
|
|
1036
|
+
"$comment": [
|
|
1037
|
+
"Bảng phụ ngoài TSV chính. Nằm ngoài SoT cho tới G30 — dù nó là NGUỒN của hai cờ 🔴",
|
|
1038
|
+
"chặn PR (SEAM_UNWIRED, STUB_UNRESOLVED). Đổi tên/thứ tự cột mà không ai bắt được."
|
|
1039
|
+
],
|
|
1040
|
+
"name": "_seams.tsv",
|
|
1041
|
+
"path": "{trace_dir}/{domain}/{prd-slug}/_seams.tsv",
|
|
1042
|
+
"columns": [
|
|
1043
|
+
"kind",
|
|
1044
|
+
"name",
|
|
1045
|
+
"consumer_uc",
|
|
1046
|
+
"owner_uc",
|
|
1047
|
+
"artifact",
|
|
1048
|
+
"binding",
|
|
1049
|
+
"status",
|
|
1050
|
+
"last_updated"
|
|
1051
|
+
],
|
|
1052
|
+
"written_by": [
|
|
1053
|
+
"generate-code",
|
|
1054
|
+
"validate-traces"
|
|
1055
|
+
],
|
|
1056
|
+
"read_by": [
|
|
1057
|
+
"validate-traces",
|
|
1058
|
+
"review-code"
|
|
1059
|
+
],
|
|
1060
|
+
"column_actors": [
|
|
1061
|
+
"generate-code",
|
|
1062
|
+
"validate-traces"
|
|
1063
|
+
],
|
|
1064
|
+
"$column_actors_note": "Chỉ hai lệnh này thao tác ở MỨC CỘT (ghi/parse từng field). review-code là consumer ở MỨC BẢNG — nó chỉ kiểm 'có dòng PENDING tương ứng trong sổ không', không đọc tên cột. Tách ra để R3 đừng đòi review-code nhắc đủ 8 tên cột."
|
|
1065
|
+
}
|
|
1066
|
+
],
|
|
1067
|
+
"queues": [
|
|
1068
|
+
{
|
|
1069
|
+
"$comment": [
|
|
1070
|
+
"Hàng đợi feedback từ tester/QC. Khai ở đây để R1 bắt được ca 'hàng đợi mất consumer'",
|
|
1071
|
+
"y như nó bắt field mất producer — đó chính là hình dạng của G26."
|
|
1072
|
+
],
|
|
1073
|
+
"name": "bug-reports",
|
|
1074
|
+
"path_key": "bug_reports_dir",
|
|
1075
|
+
"written_by": [
|
|
1076
|
+
"report-bug"
|
|
1077
|
+
],
|
|
1078
|
+
"read_by": [
|
|
1079
|
+
"fix-bug",
|
|
1080
|
+
"qc-run-test"
|
|
1081
|
+
]
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
"name": "bdd-proposals",
|
|
1085
|
+
"path_key": "bdd_proposals_dir",
|
|
1086
|
+
"written_by": [
|
|
1087
|
+
"propose-scenario"
|
|
1088
|
+
],
|
|
1089
|
+
"read_by": [
|
|
1090
|
+
"generate-bdd"
|
|
1091
|
+
]
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
"name": "prd-change-requests",
|
|
1095
|
+
"path_key": "prd_change_requests_dir",
|
|
1096
|
+
"written_by": [
|
|
1097
|
+
"propose-scenario",
|
|
1098
|
+
"extend-prd"
|
|
1099
|
+
],
|
|
1100
|
+
"read_by": [
|
|
1101
|
+
"extend-prd",
|
|
1102
|
+
"validate-traces"
|
|
1103
|
+
],
|
|
1104
|
+
"$roles_note": "extend-prd là consumer DRAIN thật (Bước 2 đọc request accepted làm nguyên liệu; Bước 6.5 đóng dấu incorporated + chuyển sang archived/ + commit) — nên nó vừa read vừa write. validate-traces Step 7b chỉ ĐẾM và nhắc (không drain). G26 đóng đủ 3 phần từ đây."
|
|
1105
|
+
}
|
|
1106
|
+
],
|
|
1107
|
+
"vocabularies": {
|
|
1108
|
+
"$comment": "Mọi giá trị phải xuất hiện ở ít nhất một actor — giá trị chết là dấu hiệu contract lệch.",
|
|
1109
|
+
"$lint_binding_comment": [
|
|
1110
|
+
"BINDING CHO lint-trace (G38). R6 canh 'giá trị có được actor nào DÙNG không' — đó là",
|
|
1111
|
+
"câu hỏi về contract. Nhưng nó không trả lời được 'file .tsv THẬT có tuân enum này không',",
|
|
1112
|
+
"vì không rule nào mở sổ thật ra xem. bin/lint-trace.js làm việc đó, và nó cần biết mỗi",
|
|
1113
|
+
"vocabulary neo vào ĐÂU. Mỗi vocabulary PHẢI khai đúng một trong:",
|
|
1114
|
+
" column → một cột của TSV chính",
|
|
1115
|
+
" columns → nhiều cột của TSV chính",
|
|
1116
|
+
" aux_table + aux_column → một cột của bảng phụ trong aux_tables",
|
|
1117
|
+
" filename_segment → một đoạn trong tên file sổ",
|
|
1118
|
+
" $lint → cố ý ngoài phạm vi lint, PHẢI nêu lý do",
|
|
1119
|
+
"Thiếu tất cả → self-check.js R8a fail build. Đây là van chống lặp lại chính G38:",
|
|
1120
|
+
"thêm vocabulary mới mà quên dạy checker thì build đỏ, không phải 6 tháng sau mới biết."
|
|
1121
|
+
],
|
|
1122
|
+
"trace_status": {
|
|
1123
|
+
"values": [
|
|
1124
|
+
"OK",
|
|
1125
|
+
"DRIFT",
|
|
1126
|
+
"GAP",
|
|
1127
|
+
"UNTRACKED",
|
|
1128
|
+
"ORPHANED"
|
|
1129
|
+
],
|
|
1130
|
+
"column": "status"
|
|
1131
|
+
},
|
|
1132
|
+
"platform": {
|
|
1133
|
+
"$comment": [
|
|
1134
|
+
"PLATFORM = DELIVERY SURFACE, không phải tech stack. `webview` là surface thứ tư có thật:",
|
|
1135
|
+
"một bundle web nhúng trong app native — không phải `web` (browser) và không phải `app`",
|
|
1136
|
+
"(native). Nó có BDD riêng (tương tác khác), design-spec riêng, và repo riêng.",
|
|
1137
|
+
"",
|
|
1138
|
+
"VÌ SAO PHẢI THÊM (báo cáo từ project thật, v0.7.0): framework DẠY `webview` ở BỐN chỗ —",
|
|
1139
|
+
" templates/project-context.yaml FORM C lấy webview mini-game làm ví dụ",
|
|
1140
|
+
" steps/context-loader.md 2c ví dụ đầy đủ: bdd/webview/UC1.feature",
|
|
1141
|
+
" commands/setup-ai-first prompt tự đưa ra `learning:webview:dap-chuot:phaser-game`",
|
|
1142
|
+
" modules/phaser-game stack-profile có mục build cho webview",
|
|
1143
|
+
"— rồi TỪ CHỐI nó ở tầng kiểm. lint-trace T5 là `err`, và validate-traces Step 1.0 DỪNG",
|
|
1144
|
+
"NGAY khi lint exit 1 ⇒ project dùng đúng ví dụ của framework mất TOÀN BỘ audit.",
|
|
1145
|
+
"",
|
|
1146
|
+
"Đổi tên sổ KHÔNG phải đường ra: nó phá khoá routing `by_prd_slug`, lệch với",
|
|
1147
|
+
"@trace.platform trong .feature, và gộp hai surface vào một sổ làm sc_id đụng nhau (mỗi",
|
|
1148
|
+
"platform đánh SC từ 1).",
|
|
1149
|
+
"",
|
|
1150
|
+
"NỢ CÒN LẠI — danh sách này vẫn ĐÓNG: project cần `desktop`/`tv`/`mini-program`/`cli` sẽ",
|
|
1151
|
+
"bị chặn y như vậy và phải chờ một bản release. Nguyên nhân gốc là `platform` được xử lý",
|
|
1152
|
+
"như enum ĐÓNG trong contract nhưng MỌI code path sinh ra nó đều MỞ (setup-ai-first nhận",
|
|
1153
|
+
"chuỗi bất kỳ · context-loader 2b đọc sub-key bất kỳ · generate-bdd ghi bdd/{platform}/",
|
|
1154
|
+
"không kiểm gì). Cách sửa đúng là cho project TỰ KHAI thêm platform trong",
|
|
1155
|
+
"project-context.yaml và để lint-trace đọc — giữ được tính năng bắt typo của T5 mà không",
|
|
1156
|
+
"cần release cho từng surface mới. Đang hoãn có chủ ý, làm ở đợt sau."
|
|
1157
|
+
],
|
|
1158
|
+
"values": [
|
|
1159
|
+
"web",
|
|
1160
|
+
"app",
|
|
1161
|
+
"system",
|
|
1162
|
+
"webview"
|
|
1163
|
+
],
|
|
1164
|
+
"filename_segment": "{UC-ID}-{platform}.tsv",
|
|
1165
|
+
"$filename_note": "Tên sổ là nơi DUY NHẤT mang platform của row — validate-traces Step 2 lấy platform từ đây để tìm .feature đúng thư mục con. Sổ thiếu đoạn này thì cả sổ vô hình (đúng hình dạng G3/G8)."
|
|
1166
|
+
},
|
|
1167
|
+
"approval_status": {
|
|
1168
|
+
"values": [
|
|
1169
|
+
"draft",
|
|
1170
|
+
"in-review",
|
|
1171
|
+
"approved"
|
|
1172
|
+
],
|
|
1173
|
+
"columns": [
|
|
1174
|
+
"prd_status",
|
|
1175
|
+
"uc_status"
|
|
1176
|
+
]
|
|
1177
|
+
},
|
|
1178
|
+
"fe_phase": {
|
|
1179
|
+
"values": [
|
|
1180
|
+
"ui",
|
|
1181
|
+
"integrated"
|
|
1182
|
+
],
|
|
1183
|
+
"column": "fe_phase"
|
|
1184
|
+
},
|
|
1185
|
+
"dev_selftest_status": {
|
|
1186
|
+
"$comment": [
|
|
1187
|
+
"G49 — hai cột này mang enum nhưng trước đó KHÔNG có vocabulary, nên lint T3 không canh:",
|
|
1188
|
+
"`dev_selftest = passed`, `qc_status = OK`, `qc_status = pending` đều đi qua sạch.",
|
|
1189
|
+
"Mà đây là hai cột của G28 ('cờ nói dối') và là hai cột có NHIỀU NGƯỜI GHI NHẤT trong",
|
|
1190
|
+
"schema — 5 lệnh và 3 lệnh, mỗi lệnh ở một nhánh điều kiện khác nhau, tất cả bằng prose.",
|
|
1191
|
+
"Cột dễ lệch giá trị nhất trong sổ, và là cột duy nhất mang enum mà không được canh.",
|
|
1192
|
+
"",
|
|
1193
|
+
"VÌ SAO SỐNG ĐƯỢC QUA G30: G30 mở phạm vi schema cho TAG (@trace.*). Hai cột này không",
|
|
1194
|
+
"có tag tương ứng — chúng chỉ sống trong TSV. Nên chúng nằm ngoài lăng kính của G30, và",
|
|
1195
|
+
"trước G38 thì không có lăng kính nào soi cột-không-có-tag."
|
|
1196
|
+
],
|
|
1197
|
+
"values": [
|
|
1198
|
+
"pass",
|
|
1199
|
+
"fail",
|
|
1200
|
+
"not_run"
|
|
1201
|
+
],
|
|
1202
|
+
"column": "dev_selftest"
|
|
1203
|
+
},
|
|
1204
|
+
"qc_run_status": {
|
|
1205
|
+
"$comment": "Xem dev_selftest_status. Có thêm `skip` — QC chủ động bỏ qua scenario (khác not_run: chưa chạy).",
|
|
1206
|
+
"values": [
|
|
1207
|
+
"pass",
|
|
1208
|
+
"fail",
|
|
1209
|
+
"skip",
|
|
1210
|
+
"not_run"
|
|
1211
|
+
],
|
|
1212
|
+
"column": "qc_status"
|
|
1213
|
+
},
|
|
1214
|
+
"seam_status": {
|
|
1215
|
+
"values": [
|
|
1216
|
+
"PENDING",
|
|
1217
|
+
"READY",
|
|
1218
|
+
"RESOLVED"
|
|
1219
|
+
],
|
|
1220
|
+
"aux_table": "_seams.tsv",
|
|
1221
|
+
"aux_column": "status"
|
|
1222
|
+
},
|
|
1223
|
+
"audit_flags": {
|
|
1224
|
+
"$lint": "n/a — không sống trong TSV. Cờ audit được tính lúc chạy và sống trong trace-report.json (issues + summary counter); R7 canh đủ ba tầng của chúng. lint-trace chỉ kiểm file trên đĩa, nên không có gì để neo.",
|
|
1225
|
+
"values": [
|
|
1226
|
+
"PRD_UNTRACKED_EDIT",
|
|
1227
|
+
"PRD_DRIFT",
|
|
1228
|
+
"PRD_STALE_REF",
|
|
1229
|
+
"BDD_DRIFT",
|
|
1230
|
+
"TECHDOC_DRIFT",
|
|
1231
|
+
"TECHDOC_STALE_REF",
|
|
1232
|
+
"FE_TECHDOC_DRIFT",
|
|
1233
|
+
"TECHDOC_STALE_VS_BDD",
|
|
1234
|
+
"DESIGNSPEC_DRIFT",
|
|
1235
|
+
"DESIGNSPEC_STALE_VS_BDD",
|
|
1236
|
+
"TRACE_ORPHAN",
|
|
1237
|
+
"LEDGER_BEHIND_CODE",
|
|
1238
|
+
"SEAM_UNWIRED",
|
|
1239
|
+
"STUB_UNRESOLVED",
|
|
1240
|
+
"SEAM_PENDING",
|
|
1241
|
+
"STUB_PENDING",
|
|
1242
|
+
"SERVICE_UNROUTED"
|
|
1243
|
+
]
|
|
1244
|
+
}
|
|
1245
|
+
},
|
|
1246
|
+
"gate": {
|
|
1247
|
+
"$comment": [
|
|
1248
|
+
"CỔNG CHẶN PR (G39). README khai bằng chữ in đậm rằng 4 cờ này 'chặn PR', kèm câu",
|
|
1249
|
+
"'build xanh + test từng-UC xanh KHÔNG phát hiện được' — đó là điểm bán hàng cốt lõi.",
|
|
1250
|
+
"Nhưng trước G39 không có gì chặn: 0 CI, 0 git hook, 0 exit code. /validate-traces in",
|
|
1251
|
+
"một report vào terminal Claude Code, nơi không CI nào đọc được. Kỷ luật là honor-system,",
|
|
1252
|
+
"và cái gì không chặn thì sau sprint thứ ba không ai làm.",
|
|
1253
|
+
"",
|
|
1254
|
+
"bin/gate-trace.js đọc khối này để biết ĐẾM CỜ NÀO — không hard-code. Vì sao quan trọng:",
|
|
1255
|
+
"gate đọc summary[counter]. Nếu counter bị đổi tên mà gate không biết, `undefined > 0`",
|
|
1256
|
+
"là false ⇒ GATE PASS TRÊN CODE HỎNG. Đó là false-green im lặng, đúng hình dạng G1.",
|
|
1257
|
+
"Nên gate PHẢI fail khi counter nó chờ không có mặt trong report, và self-check R9 canh",
|
|
1258
|
+
"cả hai đầu (counter có trong summary của validate-traces · issues_key có trong issues).",
|
|
1259
|
+
"",
|
|
1260
|
+
"Cờ 🟠 (PRD_DRIFT, BDD_DRIFT, TECHDOC_DRIFT, …) CỐ Ý không nằm đây — chúng là 'code chưa",
|
|
1261
|
+
"theo kịp spec', một loại nợ khác, không làm hỏng luồng đang chạy. Chặn PR vì nợ là làm",
|
|
1262
|
+
"cổng bị tắt. Xem README §Traceability."
|
|
1263
|
+
],
|
|
1264
|
+
"report_path": "{trace_dir}/trace-report.json",
|
|
1265
|
+
"config_preconditions": {
|
|
1266
|
+
"$comment": [
|
|
1267
|
+
"TẦNG G0 — 'sổ có ĐƯỢC BẢO VỆ không?', hỏi TRƯỚC cả ba tầng kia.",
|
|
1268
|
+
"",
|
|
1269
|
+
"Vì sao tách khỏi `blocking`: `blocking` có nghĩa hẹp là CODE ĐANG HỎNG (4 cờ 🔴), và",
|
|
1270
|
+
"R9(e) tồn tại để giữ đúng ranh giới đó — nó fail build nếu ai nhét một cờ NỢ (🟠) vào.",
|
|
1271
|
+
"Hai điều kiện dưới đây thuộc loại THỨ BA: chưa có gì sai, nhưng LƯỚI AN TOÀN ĐANG TẮT.",
|
|
1272
|
+
"Ví như: động cơ hỏng (🔴) · đến hạn thay dầu (🟠) · CHƯA CÀI DÂY AN TOÀN (G0).",
|
|
1273
|
+
"Trộn chúng vào `blocking` là làm mờ chính ranh giới R9(e) bảo vệ.",
|
|
1274
|
+
"",
|
|
1275
|
+
"Vì sao hỏi TRƯỚC: G1 kiểm rất kỹ cấu trúc của một quyển sổ mà có thể KHÔNG NẰM TRONG",
|
|
1276
|
+
"GIT. Kiểm cấu trúc của thứ sắp mất thì vô nghĩa.",
|
|
1277
|
+
"",
|
|
1278
|
+
"Cách hoạt động: cả hai điều kiện đã được `bin/lint-trace.js` phát hiện dưới dạng WARN.",
|
|
1279
|
+
"gate NÂNG chúng thành lỗi chặn. Một implementation, hai mức nghiêm trọng — cố ý:",
|
|
1280
|
+
" pre-push (lint) → NHẮC. Chặn push vì một dòng cấu hình sẽ dạy dev gõ --no-verify,",
|
|
1281
|
+
" và mất luôn phần lint THẬT (sổ hỏng cấu trúc).",
|
|
1282
|
+
" CI (gate) → CHẶN. Đây là chỗ đúng để chặn.",
|
|
1283
|
+
"Cùng cách phân vai G39 đã chọn cho pre-push vs CI."
|
|
1284
|
+
],
|
|
1285
|
+
"promote_lint_rules": [
|
|
1286
|
+
{
|
|
1287
|
+
"rule": "T13",
|
|
1288
|
+
"why": "KHÔNG KIỂM ĐƯỢC hai điều kiện kia — thiếu binary `git`, hoặc sổ không nằm trong repo git nào. Đây là loại THỨ TƯ, khác cả ba loại còn lại: không phải 'đang có cái sai' (🔴), không phải 'nợ' (🟠), cũng không phải 'bảo vệ đang tắt' (T10/T11) — mà là 'KHÔNG BIẾT bảo vệ có bật hay không'. Trước T13, ca này làm G0 in ra `sổ được bảo vệ — 2/2 điều kiện`: một lời KHẲNG ĐỊNH trên bằng chứng chưa bao giờ được thu, tệ hơn im lặng (cùng hình dạng G55). Ca thường gặp nhất là CI dùng image tối giản — node:*-alpine và node:*-slim đều KHÔNG có git — tức chính môi trường mà cổng này tồn tại để chạy."
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
"rule": "T11",
|
|
1292
|
+
"why": "sổ trace đang bị gitignore — nó KHÔNG được lưu vào git, mất là mất toàn bộ (G29)"
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
"rule": "T10",
|
|
1296
|
+
"why": "sổ thiếu luật merge — hai nhánh cùng ghi sẽ mất row của nhau, im lặng (G40)"
|
|
1297
|
+
}
|
|
1298
|
+
]
|
|
1299
|
+
},
|
|
1300
|
+
"checkpoint_levels": {
|
|
1301
|
+
"$comment": [
|
|
1302
|
+
"MỨC CHẶN CHECKPOINT CỦA TỪNG LỆNH (nợ 'nhãn chặn cứng' sau G41).",
|
|
1303
|
+
"",
|
|
1304
|
+
"G41 viết ba mức vào steps/gate.md Bước 3a — nhưng KHÔNG lệnh nào tự khai mình thuộc",
|
|
1305
|
+
"mức nào. Nên agent phải TỰ SUY từ bảng đó mỗi lần đọc: '/extend-prd sửa một PRD đã",
|
|
1306
|
+
"duyệt — có tính là ghi đè file đã có không?'. Suy đúng thì không sao; suy sai một lần",
|
|
1307
|
+
"theo hướng nhẹ hơn thì `--yes` bỏ qua được một cổng đáng ra KHÔNG BAO GIỜ được bỏ.",
|
|
1308
|
+
"",
|
|
1309
|
+
"Đây là hình dạng đã gặp bốn lần trong loạt GAP này: luật ĐÚNG, viết RÕ, và KHÔNG AI",
|
|
1310
|
+
"CANH. G1 ('phải bump sc_version') · G28 ('đổi spec thì hạ qc_status') · G41 ('read-only",
|
|
1311
|
+
"được miễn CHECKPOINT' — gate không thi hành) · và cái này. Ba lần trước đều chữa bằng",
|
|
1312
|
+
"cùng một cách: khai tường minh + để máy canh. R11 là phần 'máy canh'.",
|
|
1313
|
+
"",
|
|
1314
|
+
"KHÔNG liệt kê `normal`: nó là mặc định, và liệt kê ra là tạo một danh sách phải bảo",
|
|
1315
|
+
"trì mãi mãi — thêm lệnh mới mà quên thêm vào đó thì lại sai lần nữa.",
|
|
1316
|
+
"",
|
|
1317
|
+
"PHẠM VI: `hard` là 'ghi đè thứ NGƯỜI DÙNG ĐÃ DUYỆT'. /generate-code · /generate-bdd ·",
|
|
1318
|
+
"/generate-tech-docs CỐ Ý không nằm đây — chúng ghi thứ SINH RA ĐƯỢC từ spec, không phải",
|
|
1319
|
+
"thứ người dùng đã duyệt bằng tay. Ba script migrate cũng không: chúng là CLI, dry-run",
|
|
1320
|
+
"mặc định, không đi qua gate.",
|
|
1321
|
+
"",
|
|
1322
|
+
"/map-testids TỪNG ở danh sách miễn trừ trên, và ĐÓ LÀ SAI (G83). Lý do cũ: 'nó ghi thứ",
|
|
1323
|
+
"SINH RA ĐƯỢC từ spec'. Dữ liệu thật phủ nhận tiền đề đó — 28/28 tech-doc của một dự án",
|
|
1324
|
+
"đang chạy có §4.5.6 do SA VIẾT TAY, theo quy ước riêng (`uc{n}-z2-region`,",
|
|
1325
|
+
"`uc1-z2-rank-avatar / uc1-z2-rank-name`) mà /map-testids KHÔNG tái tạo được: quy ước của",
|
|
1326
|
+
"nó là {uc-lower}-{screen}-{element}-{type}. Và cả 28 doc đều THIẾU @trace.testid_attr,",
|
|
1327
|
+
"tức lệnh này CHƯA TỪNG CHẠY ở đó — mọi bảng đang có đều do người viết.",
|
|
1328
|
+
"",
|
|
1329
|
+
"BÀI HỌC, ghi lại để không ai khôi phục miễn trừ cũ: 'sinh lại được' là tính chất của",
|
|
1330
|
+
"CÔNG CỤ; 'bản đang có do ai viết' là sự thật về DỮ LIỆU. Chỉ cái thứ hai quyết định có",
|
|
1331
|
+
"mất gì khi ghi đè. Khi miễn một lệnh khỏi cổng vì 'nó sinh lại được', hỏi tiếp: AI đã",
|
|
1332
|
+
"sinh ra bản đang có?"
|
|
1333
|
+
],
|
|
1334
|
+
"label_marker": "Checkpoint:",
|
|
1335
|
+
"hard": [
|
|
1336
|
+
{
|
|
1337
|
+
"cmd": "generate-prd",
|
|
1338
|
+
"why": "ghi đè PRD đã có → mất changelog, ĐÁNH SỐ LẠI BR, phá @trace.business_rules trong mọi .feature đã sinh"
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
"cmd": "extend-prd",
|
|
1342
|
+
"why": "sửa PRD đã DUYỆT"
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
"cmd": "amend-prd",
|
|
1346
|
+
"why": "SỬA TẠI CHỖ một AC/BR/UC đã duyệt — thao tác ghi DUY NHẤT trong framework được phép làm output KHÔNG phải superset của bản cũ"
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
"cmd": "refine-prd",
|
|
1350
|
+
"why": "--resume áp findings trực tiếp vào PRD"
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
"cmd": "generate-architecture",
|
|
1354
|
+
"why": "ghi đè architecture.md đã verified_by một người thật"
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
"cmd": "dev-gen-test",
|
|
1358
|
+
"why": "ghi đè file test đã có → XOÁ bản sửa tay của dev (mock, fixture, expectation đã chỉnh) mà chính /dev-run-test bảo họ làm",
|
|
1359
|
+
"$comment": [
|
|
1360
|
+
"G84 — CÙNG KHUÔN G77, khác lane. Bốn trên bốn giống nhau:",
|
|
1361
|
+
" /qc-run-test (G77) /dev-gen-test (G84)",
|
|
1362
|
+
" ai sửa tay QC — 'script-bug' Dev — 'fix test (sai expectation)'",
|
|
1363
|
+
" luật chạy lại ✅ đã thêm ❌ không có",
|
|
1364
|
+
" nhãn checkpoint ✅ hard ❌ normal",
|
|
1365
|
+
" §Output khai file ghi ✅ đã thêm ❌ chỉ khai sổ trace",
|
|
1366
|
+
"",
|
|
1367
|
+
"BẰNG CHỨNG dev SỬA TAY — chính /dev-run-test nói:",
|
|
1368
|
+
" :260 'Test fail → /fix-bug {TICKET_ID} (bug thật) hoặc FIX TEST (sai expectation)'",
|
|
1369
|
+
" :137 'TimeoutError | Test gọi LLM endpoint live | Thêm mock; kiểm tra test fixture'",
|
|
1370
|
+
"",
|
|
1371
|
+
"PHẠM VI: chỉ `hard` khi file test ĐÃ TỒN TẠI. Lần sinh đầu đi thẳng.",
|
|
1372
|
+
"",
|
|
1373
|
+
"KHÁC G77 MỘT ĐIỂM: trạm 5 QC có vòng đời CHẠY nhiều / SINH ít nên mặc định của nó là",
|
|
1374
|
+
"'CHẠY, đừng sinh lại'. /dev-gen-test CHỈ SINH, không chạy gì — nên mặc định ở đây là",
|
|
1375
|
+
"'sinh phần THIẾU, giữ phần ĐÃ CÓ'. Copy nguyên mặc định của G77 sang là copy nhầm ngữ cảnh.",
|
|
1376
|
+
"",
|
|
1377
|
+
"BÀI HỌC: vá một lỗ trong một LANE xong thì việc tiếp theo KHÔNG phải đi tiếp trong lane",
|
|
1378
|
+
"đó — mà là hỏi 'lane nào khác có cấu trúc GƯƠNG?'. G77 vá lane QC; lane dev có cấu trúc",
|
|
1379
|
+
"gương (sinh test → chạy → sửa → chạy lại) và lọt thêm một vòng nữa vì bản rà khuôn G67",
|
|
1380
|
+
"khai phạm vi là '6 lệnh QC'."
|
|
1381
|
+
]
|
|
1382
|
+
},
|
|
1383
|
+
{
|
|
1384
|
+
"cmd": "map-testids",
|
|
1385
|
+
"why": "ghi đè §4.5.6 đã có → ĐỔI id hợp đồng mà SA viết tay, và kéo theo Step 5b hạ qc_status + bump tech_doc_revision cho một hợp đồng CHƯA HỎNG",
|
|
1386
|
+
"$comment": [
|
|
1387
|
+
"G83 — lệnh này TỪNG được miễn `hard` có chủ ý, xem $comment của checkpoint_levels.",
|
|
1388
|
+
"Chỉ `hard` KHI §4.5.6 đã có row. Tech-doc chưa có bảng (brownfield thật) là ca lệnh này",
|
|
1389
|
+
"SINH RA ĐỂ PHỤC VỤ — bắt CHECKPOINT cứng ở đó là ồn vô cớ.",
|
|
1390
|
+
"",
|
|
1391
|
+
"hard KHÔNG tự bảo toàn gì. Thứ thật sự giữ hợp đồng là luật reverse-document cho BẢNG ở",
|
|
1392
|
+
"Step 2: id đã có trong bảng → DÙNG LẠI AS-IS, chỉ gán mới cho element chưa có row.",
|
|
1393
|
+
"Luật đó vốn đã tồn tại CHO CODE ('nếu element đã có test-id → dùng lại as-is') mà không",
|
|
1394
|
+
"có vế tương ứng cho bảng — trong khi BẢNG mới là hợp đồng, code là bên phải tuân theo."
|
|
1395
|
+
]
|
|
1396
|
+
},
|
|
1397
|
+
{
|
|
1398
|
+
"cmd": "qc-run-test",
|
|
1399
|
+
"why": "ghi đè script Python đã có → XOÁ bản sửa `script-bug` mà chính lệnh này bảo QC tự sửa bằng tay",
|
|
1400
|
+
"$comment": [
|
|
1401
|
+
"G77 — NẶNG HƠN G67, và lý do nằm ở TRIỆU CHỨNG.",
|
|
1402
|
+
"",
|
|
1403
|
+
"Vòng đời bình thường của trạm 5: sinh → chạy → đỏ → QC SỬA TAY → chạy lại. Bước cuối là",
|
|
1404
|
+
"bước xoá. §Phân loại FAIL khai tường minh: `script-bug` ⇒ 'QC tự sửa. Không mở bug'.",
|
|
1405
|
+
"",
|
|
1406
|
+
"Triệu chứng sau khi mất bản sửa: 'tôi vừa sửa mà vẫn đỏ y hệt' — TRÙNG KHÍT với triệu",
|
|
1407
|
+
"chứng của một bản sửa CHƯA ĐÚNG. Nên nó hỏng đúng vào lúc người ta đang sẵn sàng tin là",
|
|
1408
|
+
"MÌNH sai, và vòng lặp sửa-lại có thể chạy nhiều lần trước khi ai nghi ngờ công cụ.",
|
|
1409
|
+
"",
|
|
1410
|
+
"LỖI GỐC: lệnh KHÔNG CÓ §Output — nó không khai mình ghi cái gì, ở đâu (đường dẫn chỉ nằm",
|
|
1411
|
+
"trong modules/qc-playwright/stack-profile.yaml). Một lệnh không khai mình ghi gì thì không",
|
|
1412
|
+
"ai nghĩ tới việc bảo vệ thứ nó ghi.",
|
|
1413
|
+
"",
|
|
1414
|
+
"MẶC ĐỊNH PHẢI ĐẢO: vòng đời trạm 5 là CHẠY nhiều, SINH ít. Mặc định cũ sinh lại mỗi lần",
|
|
1415
|
+
"chạy, dù không có gì đổi."
|
|
1416
|
+
]
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
"cmd": "qc-design-test",
|
|
1420
|
+
"why": "ghi đè *.Test.md đã qua cổng HITL /qc-review → mất `Status` đã duyệt, `Expected Result` đã sửa theo finding, dấu 🚫 Block vừa gỡ; và ĐÁNH SỐ LẠI TC_<FEATURE>_NNN mà REVIEW_<FEATURE>.md đang trỏ vào",
|
|
1421
|
+
"$comment": [
|
|
1422
|
+
"G78 — cùng khuôn G67/G77 nhưng 🟠, vì /qc-review chạy lại được và bắt lại phần lớn finding.",
|
|
1423
|
+
"Cái mất là MỘT VÒNG REVIEW ĐẦY ĐỦ, không phải một sự thật sai — nhưng nó mất mà không ai",
|
|
1424
|
+
"biết vì sao phải soát lại.",
|
|
1425
|
+
"",
|
|
1426
|
+
"Ô ít ai nghĩ tới: REVIEW_<FEATURE>.md nằm CẠNH file TC trong cùng thư mục và tham chiếu TC",
|
|
1427
|
+
"THEO SỐ. Đánh số lại là làm cả biên bản soát trỏ sai — cùng hình dạng 🚫 Block ở G67, khác",
|
|
1428
|
+
"cặp file.",
|
|
1429
|
+
"",
|
|
1430
|
+
"§duplicate-check KHÔNG phải lưới cho ca này: nó chống VIẾT TRÙNG, không chống GHI ĐÈ. Tên",
|
|
1431
|
+
"nghe giống nhau đủ để tưởng đã có người lo."
|
|
1432
|
+
]
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
"cmd": "qc-analyze",
|
|
1436
|
+
"why": "ghi đè DOC_GAP.md đã có → mất cột Trạng thái/Câu trả lời (PO điền TAY, KHÔNG sinh lại được), ĐÁNH SỐ LẠI GAP-ID, phá 🚫 Block trong mọi .Test.md đã sinh",
|
|
1437
|
+
"$comment": [
|
|
1438
|
+
"G67 — KHỚP BA TRÊN BA với lý do của generate-prd, và đó chính là lập luận:",
|
|
1439
|
+
" generate-prd → PRD | qc-analyze → DOC_GAP.md",
|
|
1440
|
+
" mất changelog | mất Trạng thái + Câu trả lời (PO điền tay)",
|
|
1441
|
+
" ĐÁNH SỐ LẠI BR | ĐÁNH SỐ LẠI GAP-UC{N}-{nnn}",
|
|
1442
|
+
" phá @trace.business_rules | phá 🚫 Block trong mọi .Test.md",
|
|
1443
|
+
" trong mọi .feature |",
|
|
1444
|
+
"",
|
|
1445
|
+
"VÌ SAO TRƯỚC ĐÓ BỊ XẾP `normal`: danh sách hard là ALLOWLIST và mặc định là `normal`.",
|
|
1446
|
+
"Schema tự thú điểm yếu đó ngay ở $comment của checkpoint_levels: 'thêm lệnh mới mà quên",
|
|
1447
|
+
"thêm vào đó thì lại sai lần nữa'. Nó đã sai đúng như vậy. R11 KHÔNG bắt được vì R11 chỉ",
|
|
1448
|
+
"kiểm nhãn-trong-file có khớp schema không — hai bên khớp nhau, cái sai nằm ở PHÂN LOẠI.",
|
|
1449
|
+
"",
|
|
1450
|
+
"PHẠM VI: chỉ `hard` KHI DOC_GAP.md ĐÃ TỒN TẠI. Lần chạy đầu không ghi đè gì; bắt CHECKPOINT",
|
|
1451
|
+
"cứng ở đó là ồn vô cớ. Nhãn khai mức CAO NHẤT CÓ THỂ; phần rẽ nhánh nằm trong lệnh.",
|
|
1452
|
+
"",
|
|
1453
|
+
"hard KHÔNG TỰ BẢO TOÀN DỮ LIỆU — nó chỉ làm người ta dừng lại nhìn. Luật merge",
|
|
1454
|
+
"'thêm-không-thay' trong chính lệnh mới là thứ giữ được hai ô của PO. Xem §Chạy lại của",
|
|
1455
|
+
"commands/qc-analyze.tmpl.",
|
|
1456
|
+
"",
|
|
1457
|
+
"Đường lập lại từ trắng: --force (gate.bypass_flags), và report PHẢI khai số câu trả lời bị xoá."
|
|
1458
|
+
]
|
|
1459
|
+
}
|
|
1460
|
+
],
|
|
1461
|
+
"none": [
|
|
1462
|
+
{
|
|
1463
|
+
"cmd": "review-code",
|
|
1464
|
+
"why": "read-only"
|
|
1465
|
+
},
|
|
1466
|
+
{
|
|
1467
|
+
"cmd": "validate-traces",
|
|
1468
|
+
"why": "read-only (ghi trace-report.json + TSV status, không đụng spec/code)"
|
|
1469
|
+
},
|
|
1470
|
+
{
|
|
1471
|
+
"cmd": "debug",
|
|
1472
|
+
"why": "read-only"
|
|
1473
|
+
},
|
|
1474
|
+
{
|
|
1475
|
+
"cmd": "review-context",
|
|
1476
|
+
"why": "read-only (ghi findings vào .agent/review/)"
|
|
1477
|
+
},
|
|
1478
|
+
{
|
|
1479
|
+
"cmd": "review-tech-docs",
|
|
1480
|
+
"why": "read-only (ghi findings vào .agent/review/)"
|
|
1481
|
+
}
|
|
1482
|
+
]
|
|
1483
|
+
},
|
|
1484
|
+
"bypass_flags": {
|
|
1485
|
+
"$comment": [
|
|
1486
|
+
"MỘT TÊN DUY NHẤT CHO VIỆC 'TÔI BIẾT ĐIỀU KIỆN NÀY, VẪN MUỐN CHẠY': --force.",
|
|
1487
|
+
"",
|
|
1488
|
+
"VÌ SAO CÓ KHỐI NÀY: trước nó, mỗi chỗ bỏ qua một điều kiện lại đặt một tên riêng —",
|
|
1489
|
+
"--force (generate-code, bỏ guard status), --include-draft (qc-scope, bỏ chặn BDD nháp),",
|
|
1490
|
+
"và exec-d0-b5 còn đang đề xuất --no-testid-contract 'theo đúng tinh thần --include-draft'.",
|
|
1491
|
+
"Ba tên cho một hành vi, và cái thứ ba chưa kịp sinh ra đã thấy nó sẽ là cái thứ ba.",
|
|
1492
|
+
"Người dùng phải nhớ mỗi lệnh một từ khác nhau để làm CÙNG một việc — và cái giá không",
|
|
1493
|
+
"phải là gõ sai, mà là KHÔNG BIẾT rằng có đường ra, rồi đi sửa spec cho hợp lệ giả.",
|
|
1494
|
+
"",
|
|
1495
|
+
"BA ĐIỀU KHOẢN — thiếu cái nào thì --force thành 'ghi đè tất cả' và mất hết ý nghĩa:",
|
|
1496
|
+
"",
|
|
1497
|
+
" (1) PHẠM VI KHAI TỪNG LỆNH, KHÔNG BAO GIỜ BAO TRÙM. Mỗi lệnh tự khai --force của nó",
|
|
1498
|
+
" bỏ qua ĐÚNG điều kiện nào; mọi điều kiện khác vẫn chặn. Tiền lệ đúng có sẵn:",
|
|
1499
|
+
" generate-code.tmpl §'--force có phạm vi HẸP — đây là ranh giới cứng, không phải",
|
|
1500
|
+
" khuyến nghị' … 'KHÔNG phải ghi đè tất cả'. Đó là khuôn, không phải ngoại lệ.",
|
|
1501
|
+
"",
|
|
1502
|
+
" (2) PHẢI KHAI RA ĐÃ BỎ QUA GÌ. Report in một dòng cho MỖI điều kiện bị bỏ qua.",
|
|
1503
|
+
" Một cờ chung mà im lặng thì người dùng bỏ qua X cũng bỏ qua luôn Y, Z họ chưa",
|
|
1504
|
+
" từng biết có tồn tại. Tên chung là để DỄ NHỚ, không phải để DỄ MÙ.",
|
|
1505
|
+
"",
|
|
1506
|
+
" (3) ARTIFACT PHẢI TỰ KHAI. Lần chạy có --force sinh ra file nào thì file đó mang một",
|
|
1507
|
+
" dòng nói nó dựa trên điều kiện bị bỏ qua. Cờ nằm ở dòng lệnh thì biến mất sau khi",
|
|
1508
|
+
" lệnh chạy xong; dấu nằm trong file thì đi cùng file tới người đọc sau.",
|
|
1509
|
+
"",
|
|
1510
|
+
"--force ≠ --yes. TRỤC KHÁC NHAU, KHÔNG BAO GIỜ GỘP:",
|
|
1511
|
+
" --yes = 'tôi không ngồi đây để trả lời' → bỏ qua CHECKPOINT (hỏi Y/N)",
|
|
1512
|
+
" --force = 'tôi biết điều kiện này, vẫn chạy' → bỏ qua một ĐIỀU KIỆN NGHIỆP VỤ",
|
|
1513
|
+
"Gộp là để một lần chạy headless âm thầm vượt mọi điều kiện — đúng thứ qc-scope §4 đã",
|
|
1514
|
+
"từ chối khi nó tách --include-draft khỏi --yes. Đổi TÊN không đổi lập luận đó.",
|
|
1515
|
+
"",
|
|
1516
|
+
"KHÔNG PHẢI MỌI ĐIỀU KIỆN ĐỀU --force ĐƯỢC. Điều kiện thuộc lớp 'báo cáo sai' — bỏ qua",
|
|
1517
|
+
"nó thì lệnh sinh ra một KHẲNG ĐỊNH sai chứ không phải một sản phẩm kém — là chặn cứng,",
|
|
1518
|
+
"không cờ nào qua. Ví dụ: guard tiền đề của qc-design-test (G60) — thiếu DOC_GAP.md thì",
|
|
1519
|
+
"TC bị gap chặn trông y hệt TC bình thường, và lỗi đi ra khỏi đội QC thành bug gửi PO.",
|
|
1520
|
+
"Đó không phải 'tôi biết và chấp nhận', đó là 'tôi sẽ dán nhãn sai'.",
|
|
1521
|
+
"",
|
|
1522
|
+
"CÁC TÊN ĐÃ BỎ: --include-draft (đổi thành --force ở qc-scope, 2026-09-14). KHÔNG giữ",
|
|
1523
|
+
"alias: hai tên cho một thứ chính là mầm drift mà khối này sinh ra để chặn."
|
|
1524
|
+
],
|
|
1525
|
+
"canonical_name": "--force",
|
|
1526
|
+
"never_merge_with": "--yes",
|
|
1527
|
+
"required_clauses": [
|
|
1528
|
+
"scope_declared_per_command",
|
|
1529
|
+
"report_lists_what_was_bypassed",
|
|
1530
|
+
"artifact_self_declares"
|
|
1531
|
+
],
|
|
1532
|
+
"declared_by": [
|
|
1533
|
+
{
|
|
1534
|
+
"cmd": "generate-code",
|
|
1535
|
+
"bypasses": "guard status ở §Read Trace State (row đang `OK` vẫn được gen lại)",
|
|
1536
|
+
"never_bypasses": "mất member/tag của UC khác — luôn là lỗi chặn"
|
|
1537
|
+
},
|
|
1538
|
+
{
|
|
1539
|
+
"cmd": "qc-scope",
|
|
1540
|
+
"bypasses": "chặn BDD chưa `approved` — cả cổng `0/n` cấp PRD lẫn cổng target cấp UC",
|
|
1541
|
+
"never_bypasses": "target không có trong `uc_list` (sai UC-ID / sai nền)"
|
|
1542
|
+
}
|
|
1543
|
+
],
|
|
1544
|
+
"hard_never_forceable": [
|
|
1545
|
+
{
|
|
1546
|
+
"cmd": "qc-design-test",
|
|
1547
|
+
"condition": "guard tiền đề — thiếu REQUIREMENT_ANALYSIS.md / DOC_GAP.md / TEST_PLAN.md",
|
|
1548
|
+
"why": "lớp 'báo cáo sai' (G60): thiếu DOC_GAP thì TC bị chặn mất dấu `🚫 Block`, lỗi đi ra khỏi đội QC thành bug gửi PO"
|
|
1549
|
+
}
|
|
1550
|
+
]
|
|
1551
|
+
},
|
|
1552
|
+
"audit_invalidating_tags": {
|
|
1553
|
+
"$comment": [
|
|
1554
|
+
"TAG NÀO TRONG CODE, KHI ĐỔI, LÀM AUDIT HẾT TƯƠI (nợ #4 sau Wave 1).",
|
|
1555
|
+
"",
|
|
1556
|
+
"gate chứng minh 'report khớp SỔ', không chứng minh 'sổ khớp CODE' — việc đó cần",
|
|
1557
|
+
"/validate-traces, một lệnh LLM không chạy được trong CI thường. Nên có lỗ: dev sửa",
|
|
1558
|
+
"code mà không audit lại thì sổ+report vẫn khớp nhau, gate vẫn PASS, và mọi cờ 🔴 nói",
|
|
1559
|
+
"về trạng thái TRƯỚC khi sửa. Job `require-fresh-audit` trong templates/ci/ bịt lỗ đó",
|
|
1560
|
+
"bằng một PROXY: không verify được thì ĐÒI BẰNG CHỨNG có người vừa verify.",
|
|
1561
|
+
"",
|
|
1562
|
+
"VÌ SAO LÀ TAG CHỨ KHÔNG PHẢI `^src/`: bản đầu của job hỏi 'PR có sửa src/ không?' và",
|
|
1563
|
+
"vì thế phải để TẮT mặc định — nó ĐO SAI THỨ. Framework có luật boundary-only tagging",
|
|
1564
|
+
"(docs/02-concepts/traceability.md): chỉ Controller/Handler/Middleware/Steps mang tag;",
|
|
1565
|
+
"Entity/Repository/DTO/Interface/Base KHÔNG. Nên `^src/` chặn PR chỉ sửa một DTO — một",
|
|
1566
|
+
"file 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 phần",
|
|
1567
|
+
"thật sự cần chặn.",
|
|
1568
|
+
"Câu hỏi đúng không phải 'PR có sửa src/?' mà 'PR có sửa thứ mà report đang KHẲNG ĐỊNH?'",
|
|
1569
|
+
"— và report khẳng định qua tag, tag thì nhìn thấy trong diff.",
|
|
1570
|
+
"",
|
|
1571
|
+
"PHẠM VI: chỉ 7 tag là NGUỒN của 4 cờ chặn PR. Tag version (@trace.prd_version,",
|
|
1572
|
+
"tech_doc_revision, design_spec_version) sinh ra cờ 🟠 — cờ đó cố ý không chặn, nên đổi",
|
|
1573
|
+
"chúng không cần đòi audit lại.",
|
|
1574
|
+
"",
|
|
1575
|
+
"GIỚI HẠN ĐÃ BIẾT: đổi tên class (AuthService → AuthenticationService) không chạm dòng",
|
|
1576
|
+
"tag ⇒ tag-diff bỏ lọt, dù cột `implemented_by` giờ trỏ vào tên không còn. Chấp nhận có",
|
|
1577
|
+
"chủ ý: ca đó ít gặp hơn hẳn ca sửa-code-thường, và nó KHÔNG im lặng (lần /validate-traces",
|
|
1578
|
+
"kế tiếp báo ngay). Còn báo oan thì xảy ra mỗi ngày và hậu quả là CỔNG BỊ TẮT — mất tất cả.",
|
|
1579
|
+
"Biến thể chặt hơn ('PR chạm file nào CÓ chứa tag') ghi trong comment của template.",
|
|
1580
|
+
"",
|
|
1581
|
+
"self-check R10 canh templates/ci/trace-gate.yml có nhắc đủ 7 tag này. Tag đổi tên mà",
|
|
1582
|
+
"file CI không biết ⇒ grep không khớp gì ⇒ job LUÔN XANH ⇒ cổng mù im lặng."
|
|
1583
|
+
],
|
|
1584
|
+
"$ci_templates_comment": [
|
|
1585
|
+
"MỖI file CI phải grep đủ 7 tag. Trước v0.7.2 chỉ có bản GitHub Actions được canh —",
|
|
1586
|
+
"nên khi một team dịch sang GitLab, bản dịch KHÔNG được rule nào canh, và nếu nó tụt",
|
|
1587
|
+
"lại sau schema thì grep không khớp gì ⇒ job LUÔN XANH ⇒ cổng mù trong im lặng. Đúng",
|
|
1588
|
+
"lỗi R10 tồn tại để chặn, chỉ ở một file khác loại. Thêm template CI mới thì THÊM VÀO",
|
|
1589
|
+
"danh sách này ngay — R10 canh từng file."
|
|
1590
|
+
],
|
|
1591
|
+
"ci_templates": [
|
|
1592
|
+
"templates/ci/trace-gate.yml",
|
|
1593
|
+
"templates/ci/trace-gate.gitlab-ci.yml"
|
|
1594
|
+
],
|
|
1595
|
+
"tags": [
|
|
1596
|
+
{
|
|
1597
|
+
"tag": "@trace.implements",
|
|
1598
|
+
"flags": [
|
|
1599
|
+
"ORPHANED",
|
|
1600
|
+
"TRACE_ORPHAN"
|
|
1601
|
+
]
|
|
1602
|
+
},
|
|
1603
|
+
{
|
|
1604
|
+
"tag": "@trace.verifies",
|
|
1605
|
+
"flags": [
|
|
1606
|
+
"ORPHANED",
|
|
1607
|
+
"TRACE_ORPHAN"
|
|
1608
|
+
]
|
|
1609
|
+
},
|
|
1610
|
+
{
|
|
1611
|
+
"tag": "@trace.seam_port",
|
|
1612
|
+
"flags": [
|
|
1613
|
+
"SEAM_UNWIRED"
|
|
1614
|
+
]
|
|
1615
|
+
},
|
|
1616
|
+
{
|
|
1617
|
+
"tag": "@trace.seam_pending",
|
|
1618
|
+
"flags": [
|
|
1619
|
+
"SEAM_UNWIRED"
|
|
1620
|
+
]
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
"tag": "@trace.stub",
|
|
1624
|
+
"flags": [
|
|
1625
|
+
"STUB_UNRESOLVED"
|
|
1626
|
+
]
|
|
1627
|
+
},
|
|
1628
|
+
{
|
|
1629
|
+
"tag": "@trace.stub_owner",
|
|
1630
|
+
"flags": [
|
|
1631
|
+
"STUB_UNRESOLVED"
|
|
1632
|
+
]
|
|
1633
|
+
},
|
|
1634
|
+
{
|
|
1635
|
+
"tag": "@trace.stub_for",
|
|
1636
|
+
"flags": [
|
|
1637
|
+
"STUB_UNRESOLVED"
|
|
1638
|
+
]
|
|
1639
|
+
}
|
|
1640
|
+
]
|
|
1641
|
+
},
|
|
1642
|
+
"report_root_keys": {
|
|
1643
|
+
"$comment": [
|
|
1644
|
+
"KEY Ở CẤP GỐC CỦA trace-report.json MÀ gate-trace ĐỌC (G57).",
|
|
1645
|
+
"",
|
|
1646
|
+
"VÌ SAO KHỐI NÀY TỒN TẠI: `report.domain` từng có 1 consumer (gate-trace, và nó CHẶN PR nếu",
|
|
1647
|
+
"giá trị khác 'all') và 0 producer — validate-traces không có cờ nào để đặt nó. Năm chỗ trong",
|
|
1648
|
+
"lệnh mô tả một 'domain argument' / 'domain filter' KHÔNG TỒN TẠI: ghi chú Gate ('target là",
|
|
1649
|
+
"một tên domain hoặc UC-ID cụ thể từ $ARGUMENTS') · Step 1 đọc TSV 'khớp domain target' ·",
|
|
1650
|
+
"schema report '<domain argument, or all if no filter>' · Step 8 'nếu có domain filter, chỉ",
|
|
1651
|
+
"gồm các PRD đó trong prds[]' · dòng trace-history mang field domain.",
|
|
1652
|
+
"Nên ô đó LUÔN ghi 'all', và phần kiểm của gate CHƯA BAO GIỜ chạy một lần nào.",
|
|
1653
|
+
"",
|
|
1654
|
+
"Đây ĐÚNG hình dạng R1 fail build vì nó ('field có consumer mà không có producer' — ca",
|
|
1655
|
+
"@trace.sc_version: 3 consumer, 0 producer, sống qua nhiều version không ai bắt được). Nó sống",
|
|
1656
|
+
"được vì R1 chỉ canh field trong SỔ TSV và tag trong CODE — không rule nào canh key ở cấp gốc",
|
|
1657
|
+
"của BIÊN BẢN JSON. Cùng điểm mù mà R13 vừa bịt cho `spec_baseline`.",
|
|
1658
|
+
"",
|
|
1659
|
+
"Và ghi chú Gate còn tệ hơn im lặng: một agent đọc 'target là một tên domain hoặc UC-ID' sẽ",
|
|
1660
|
+
"TIN rằng scoping hoạt động.",
|
|
1661
|
+
"",
|
|
1662
|
+
"R9(h) là phần 'máy canh': mỗi key phải CÓ MẶT trong skeleton JSON của validate-traces VÀ được",
|
|
1663
|
+
"gate-trace đọc qua `report.{key}`. Cả hai đầu, không đầu nào được lửng."
|
|
1664
|
+
],
|
|
1665
|
+
"keys": [
|
|
1666
|
+
{
|
|
1667
|
+
"key": "scope",
|
|
1668
|
+
"shape": "{ kind: all | domain | prd | uc, value: string }",
|
|
1669
|
+
"written_by": "validate-traces",
|
|
1670
|
+
"read_by": "gate-trace",
|
|
1671
|
+
"why": "Gate PHẢI chặn mọi biên bản phiến diện, không chỉ biên bản hẹp-theo-domain — xem $comment của scope_kinds cho ca false-green mà `domain` một mình không bắt được."
|
|
1672
|
+
},
|
|
1673
|
+
{
|
|
1674
|
+
"key": "domain",
|
|
1675
|
+
"shape": "tên domain, hoặc 'all'",
|
|
1676
|
+
"written_by": "validate-traces",
|
|
1677
|
+
"read_by": "gate-trace",
|
|
1678
|
+
"why": "Giữ cho TƯƠNG THÍCH NGƯỢC: biên bản sinh trước G57 không có `scope`. Gate rơi về logic cũ + in ⚠️ 'kiểm độ phủ đang ở mức yếu' thay vì fail — người dùng chưa chạy lại /validate-traces không phải là lỗi của họ. Cùng khuôn backward-compat G48 đã dùng cho `platform`."
|
|
1679
|
+
}
|
|
1680
|
+
],
|
|
1681
|
+
"scope_kinds": {
|
|
1682
|
+
"$comment": [
|
|
1683
|
+
"BẪY FALSE-GREEN mà bản fix G57 sẽ TỰ TAY MỞ nếu không siết G2 cùng lúc.",
|
|
1684
|
+
"",
|
|
1685
|
+
"gate-trace bản cũ: `if (domain !== 'all') { others = domainsOnDisk().filter(≠domain);",
|
|
1686
|
+
"if (others.length) fail }`. Trong repo MỘT domain, `others` là RỖNG ⇒ KHÔNG fail. Nên một",
|
|
1687
|
+
"biên bản hẹp-theo-PRD (hoặc hẹp-theo-UC) trong repo một domain sẽ được gate nhận là 'toàn",
|
|
1688
|
+
"bộ' — đúng cái 'cấp giấy xanh cho thứ chưa ai xem' mà chú thích của chính nó cảnh báo.",
|
|
1689
|
+
"",
|
|
1690
|
+
"Hiện tại vô hại vì không ai scope được. Nó BẬT NGAY khi scoping thành khả dụng. Nên điều",
|
|
1691
|
+
"kiện đúng là: `scope.kind !== 'all'` ⇒ FAIL, KHÔNG ngoại lệ — không phụ thuộc vào việc trên",
|
|
1692
|
+
"đĩa có bao nhiêu domain.",
|
|
1693
|
+
"",
|
|
1694
|
+
"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."
|
|
1695
|
+
],
|
|
1696
|
+
"values": [
|
|
1697
|
+
"all",
|
|
1698
|
+
"domain",
|
|
1699
|
+
"prd",
|
|
1700
|
+
"uc"
|
|
1701
|
+
],
|
|
1702
|
+
"gate_rule": "scope.kind !== 'all' ⇒ FAIL G2, không ngoại lệ",
|
|
1703
|
+
"flags": [
|
|
1704
|
+
{
|
|
1705
|
+
"flag": "--domain",
|
|
1706
|
+
"kind": "domain",
|
|
1707
|
+
"arg": "{domain}"
|
|
1708
|
+
},
|
|
1709
|
+
{
|
|
1710
|
+
"flag": "--prd",
|
|
1711
|
+
"kind": "prd",
|
|
1712
|
+
"arg": "{TICKET-ID}"
|
|
1713
|
+
},
|
|
1714
|
+
{
|
|
1715
|
+
"flag": "--uc",
|
|
1716
|
+
"kind": "uc",
|
|
1717
|
+
"arg": "{UC-ID}"
|
|
1718
|
+
}
|
|
1719
|
+
]
|
|
1720
|
+
}
|
|
1721
|
+
},
|
|
1722
|
+
"blocking": [
|
|
1723
|
+
{
|
|
1724
|
+
"counter": "orphaned_count",
|
|
1725
|
+
"issues_key": "orphaned",
|
|
1726
|
+
"label_fields": [
|
|
1727
|
+
"sc_id",
|
|
1728
|
+
"platform"
|
|
1729
|
+
],
|
|
1730
|
+
"why": "code + test còn trỏ vào scenario đã bị xoá khỏi .feature"
|
|
1731
|
+
},
|
|
1732
|
+
{
|
|
1733
|
+
"counter": "trace_orphan_count",
|
|
1734
|
+
"issues_key": "trace_orphan",
|
|
1735
|
+
"label_fields": [
|
|
1736
|
+
"sc_id",
|
|
1737
|
+
"file"
|
|
1738
|
+
],
|
|
1739
|
+
"why": "tag trong code trỏ vào SC-ID không tồn tại — không chỗ nào khác bắt được"
|
|
1740
|
+
},
|
|
1741
|
+
{
|
|
1742
|
+
"counter": "seam_unwired_count",
|
|
1743
|
+
"issues_key": "seam_unwired",
|
|
1744
|
+
"label_fields": [
|
|
1745
|
+
"port",
|
|
1746
|
+
"consumer_uc"
|
|
1747
|
+
],
|
|
1748
|
+
"why": "luồng ghép đang chạy vào stub thay vì hàng thật"
|
|
1749
|
+
},
|
|
1750
|
+
{
|
|
1751
|
+
"counter": "stub_unresolved_count",
|
|
1752
|
+
"issues_key": "stub_unresolved",
|
|
1753
|
+
"label_fields": [
|
|
1754
|
+
"artifact",
|
|
1755
|
+
"consumer_uc"
|
|
1756
|
+
],
|
|
1757
|
+
"why": "hàm rỗng chưa được lấp, nhưng caller đã gọi"
|
|
1758
|
+
}
|
|
1759
|
+
],
|
|
1760
|
+
"reconcile": {
|
|
1761
|
+
"$comment": [
|
|
1762
|
+
"Gate đọc trace-report.json — một file CÓ THỂ CŨ. Không kiểm tươi thì gate là sân khấu:",
|
|
1763
|
+
"chạy /validate-traces một lần, commit report, rồi sửa spec/code tuỳ ý — CI đọc report cũ",
|
|
1764
|
+
"và cho qua mãi. So sánh theo thời gian commit KHÔNG dùng được (report và code thường nằm",
|
|
1765
|
+
"trong CÙNG một commit, nên mốc thời gian luôn 'cũ hơn'). Cách dùng được: đối chiếu report",
|
|
1766
|
+
"với chính sổ TSV mà nó khai là đang mô tả. Bất biến dựa vào: /validate-traces Step 6 ghi",
|
|
1767
|
+
"`status` trở lại TSV, nên NGAY SAU một lần chạy, TSV và report phải khớp.",
|
|
1768
|
+
"hard = lệch thì FAIL (đếm số row là tuyệt đối, không nhập nhằng).",
|
|
1769
|
+
"soft = lệch thì WARN (phụ thuộc quy ước đếm — vd ORPHANED được report biểu diễn bằng",
|
|
1770
|
+
"boolean `orphaned` chứ không phải giá trị `status`, nên không ép cứng)."
|
|
1771
|
+
],
|
|
1772
|
+
"hard": {
|
|
1773
|
+
"total_scs": "số row dữ liệu trong mọi TSV thuộc phạm vi report"
|
|
1774
|
+
},
|
|
1775
|
+
"soft": {
|
|
1776
|
+
"drift_count": "DRIFT",
|
|
1777
|
+
"gap_count": "GAP",
|
|
1778
|
+
"untracked_count": "UNTRACKED",
|
|
1779
|
+
"orphaned_count": "ORPHANED"
|
|
1780
|
+
},
|
|
1781
|
+
"per_sc": {
|
|
1782
|
+
"$comment": [
|
|
1783
|
+
"G48 — đối chiếu TỪNG scenario thay vì chỉ tổng số. So tổng bỏ lọt ca thường gặp nhất",
|
|
1784
|
+
"khi spec tiến hoá: một SC bị xoá + một SC được thêm trong cùng một lần → tổng KHÔNG",
|
|
1785
|
+
"đổi → report cũ vẫn được coi là tươi. Khoá phải gồm platform: sc_id một mình không",
|
|
1786
|
+
"định danh được scenario ('sc_id trùng số giữa các platform là 2 scenario khác nhau').",
|
|
1787
|
+
"",
|
|
1788
|
+
"Chuẩn hoá ORPHANED: JSON CỐ Ý chỉ có 4 giá trị status, và row ORPHANED xuất ra là",
|
|
1789
|
+
"`status: DRIFT` + `orphaned: true` (validate-traces §Rules — để VS Code extension",
|
|
1790
|
+
"switch trên status không rơi vào nhánh không khớp). Nên khi so với cột `status` của",
|
|
1791
|
+
"TSV, phải quy đổi `orphaned:true` → ORPHANED TRƯỚC. Quy ước này ĐƯỢC GHI RÕ nên",
|
|
1792
|
+
"status so được ở mức `hard`; nếu nó chỉ là suy đoán thì phải để `soft`.",
|
|
1793
|
+
"",
|
|
1794
|
+
"BACKWARD-COMPAT: report sinh bởi version trước G48 không có `platform`. Gate rơi về",
|
|
1795
|
+
"so tổng số + in ⚠️ 'kiểm độ tươi đang ở mức yếu', KHÔNG fail — người dùng chưa chạy",
|
|
1796
|
+
"lại /validate-traces không phải là lỗi của họ."
|
|
1797
|
+
],
|
|
1798
|
+
"key_fields": [
|
|
1799
|
+
"sc_id",
|
|
1800
|
+
"platform"
|
|
1801
|
+
],
|
|
1802
|
+
"compare": "status",
|
|
1803
|
+
"orphaned_flag": "orphaned",
|
|
1804
|
+
"orphaned_status": "ORPHANED"
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
},
|
|
1808
|
+
"changelog_row_contract": {
|
|
1809
|
+
"$comment": [
|
|
1810
|
+
"DÒNG CHANGELOG LÀ CONTRACT MÁY ĐỌC (G52 · G53 · G58).",
|
|
1811
|
+
"",
|
|
1812
|
+
"PRD phủ nhiều UC nhưng `Version` là MỘT scalar; tech-doc gộp cấp PRD phủ nhiều UC",
|
|
1813
|
+
"nhưng `@trace.revision` cũng là một scalar. Nên sửa một UC làm MỌI UC lệch version.",
|
|
1814
|
+
"Bộ lọc ở validate-traces Step 4/5 chống báo động oan bằng cách đọc dòng changelog để",
|
|
1815
|
+
"biết lần bump đó ĐỤNG UC NÀO — nên dòng đó không phải văn xuôi cho người đọc, nó là",
|
|
1816
|
+
"ĐẦU VÀO của một phép phân loại 🟠-vs-ⓘ.",
|
|
1817
|
+
"",
|
|
1818
|
+
"VÌ SAO CẦN KHỐI NÀY: trước đó contract này là contract DUY NHẤT có consumer ĐƯỢC CANH",
|
|
1819
|
+
"(R1–R11 canh tên cột/field) mà KHÔNG producer nào được canh. Bốn lệnh ghi nó, ba hình",
|
|
1820
|
+
"dạng khác nhau, không ai kiểm — và hỏng theo CẢ HAI hướng:",
|
|
1821
|
+
" G52 /review-context --fix ghi `Auto-fix: applied {N} findings` — 0 scope ⇒ 🟠 cho MỌI",
|
|
1822
|
+
" UC. Lệnh chạy thường xuyên nhất trong lane PO là lệnh gây nhiễu nhất; sau vài",
|
|
1823
|
+
" sprint PRD_DRIFT sáng thường trực và không ai đọc nữa — mất luôn cờ đúng.",
|
|
1824
|
+
" G53 /extend-prd ghi `sửa BR8` — nêu BR mà KHÔNG nêu UC sở hữu ⇒ UC đổi thật bị xếp ⓘ",
|
|
1825
|
+
" ⇒ rào của `--realign-prd-version` (chỉ chặn 🟠) MỞ CỬA ⇒ nhãn version bị dán lại",
|
|
1826
|
+
" trên một BR vừa đổi hành vi. Đây là hướng IM LẶNG, nặng hơn hướng ỒN.",
|
|
1827
|
+
" G58 /generate-tech-docs chỉ nói `thêm một row Changelog` — không format, không ví dụ.",
|
|
1828
|
+
" Chưa nổ vì comment trong template tình cờ đúng. Nợ chờ lệch.",
|
|
1829
|
+
"",
|
|
1830
|
+
"LỜI GIẢI ĐÃ TỒN TẠI TRONG CHÍNH FRAMEWORK: nhánh BDD của review-context Fix Mode",
|
|
1831
|
+
"Phase 3 làm đúng chuẩn — bump `sc_version` theo TỪNG scenario bị đụng, liệt kê check",
|
|
1832
|
+
"nào đổi thân scenario, và nói thẳng lý do (`bump vô cớ tạo DRIFT giả và làm cờ mất giá",
|
|
1833
|
+
"trị`). Nhánh PRD ngay trên nó thì không. Khối này chỉ nâng cách làm đó lên thành",
|
|
1834
|
+
"contract cho cả bốn producer.",
|
|
1835
|
+
"",
|
|
1836
|
+
"self-check R12 là phần `máy canh`: producer phải nhắc `scope_token`, consumer phải",
|
|
1837
|
+
"nhắc `scope_token` + `neutral_marker` + `resolve_to_uc.anchor`. Marker được GHI mà",
|
|
1838
|
+
"consumer không HIỂU thì tệ hơn không có marker — nó bị coi là văn xuôi và lọt im lặng."
|
|
1839
|
+
],
|
|
1840
|
+
"scope_token": "{changelog_scope}",
|
|
1841
|
+
"scope_grammar": "Mỗi mệnh đề mở đầu bằng ĐƠN VỊ SỞ HỮU rồi tới mô tả: `{UC-ID}: {mô tả}`. Nhiều mệnh đề ngăn bằng `;`. Nội dung không thuộc UC nào → `PRD-global: {mô tả}`. BR/AC luôn đi KÈM UC sở hữu (`UC3: sửa BR8`) và KHÔNG BAO GIỜ đứng một mình (`sửa BR8`) — consumer khớp theo UC, nên một BR đứng một mình làm UC sở hữu nó bị xếp ⓘ trong khi nội dung của nó vừa đổi.",
|
|
1842
|
+
"ambiguous_fallback": "Không mệnh đề nào nêu được đơn vị sở hữu → consumer coi row là MƠ HỒ và gắn 🟠 cho MỌI UC (lưới an toàn: không suy đoán được thì quét rộng). Đây là hành vi ĐÚNG khi thiếu thông tin — nhưng là hành vi SAI khi producer CÓ thông tin mà không ghi.",
|
|
1843
|
+
"neutral_marker": "[no-behavior]",
|
|
1844
|
+
"neutral_semantics": "Hậu tố đặt sau một mệnh đề mà producer CHỨNG MINH ĐƯỢC là không đổi hành vi. Consumer: UC nêu trong mệnh đề có marker này KHÔNG bị 🟠 — nó ở lại ⓘ. Chỉ producer nào biết chính xác loại fix mình vừa áp mới được dùng; KHÔNG dùng cho người tự khai.",
|
|
1845
|
+
"neutral_checks": [
|
|
1846
|
+
{
|
|
1847
|
+
"check": "P4:skeleton",
|
|
1848
|
+
"why": "thêm section/metadata skeleton còn THIẾU — cấu trúc, không có nội dung nghiệp vụ nào mới"
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
"check": "P4:status-row",
|
|
1852
|
+
"why": "thêm `| **Status** | draft |` khi row vắng — giá trị mặc định, không phải quyết định nghiệp vụ"
|
|
1853
|
+
},
|
|
1854
|
+
{
|
|
1855
|
+
"check": "P4:drop-empty-api-section",
|
|
1856
|
+
"why": "xoá section `Existing API Contract` RỖNG ở greenfield — xoá chỗ trống"
|
|
1857
|
+
}
|
|
1858
|
+
],
|
|
1859
|
+
"not_neutral_checks": [
|
|
1860
|
+
{
|
|
1861
|
+
"check": "P1:banned-term",
|
|
1862
|
+
"why": "term đó cũng nằm trong .feature đã sinh — BDD lỗi thời THẬT về thuật ngữ (B2/C4 sẽ bắt). Đổi từ trong PRD mà không nêu UC là bỏ sót, không phải trung tính."
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
"check": "P1:tech-jargon",
|
|
1866
|
+
"why": "auto-fix của nó là `diễn đạt lại` / `chuyển Design Spec` / `bỏ về Tech Docs` — VIẾT LẠI câu văn AC/BR, và nhánh 2/3 LẤY nội dung ra khỏi PRD. Không chứng minh được là trung tính."
|
|
1867
|
+
}
|
|
1868
|
+
],
|
|
1869
|
+
"resolve_to_uc": {
|
|
1870
|
+
"required": true,
|
|
1871
|
+
"anchor": "BR/AC → UC sở hữu",
|
|
1872
|
+
"how": "Chuẩn hoá tập bị ảnh hưởng VỀ UC trước khi so: BR → UC có BR đó trong bảng Business Rule (PRD §3); AC → UC có AC đó ở dòng `**AC liên quan:**`. Không có bước này thì phép thử `UC này có trong tập?` luôn FALSE cho một row chỉ nêu BR/AC ⇒ ⓘ sai (G53). Step 4 đã mở file PRD nên không phát sinh I/O.",
|
|
1873
|
+
"fallback": "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 row là MƠ HỒ (🟠 cho mọi UC), KHÔNG bỏ qua mệnh đề đó."
|
|
1874
|
+
},
|
|
1875
|
+
"producers": [
|
|
1876
|
+
{
|
|
1877
|
+
"cmd": "refine-prd",
|
|
1878
|
+
"artifact": "PRD",
|
|
1879
|
+
"where": "Phase 3",
|
|
1880
|
+
"scope_source": "`uc_id` / `section` của các finding được chấp nhận"
|
|
1881
|
+
},
|
|
1882
|
+
{
|
|
1883
|
+
"cmd": "extend-prd",
|
|
1884
|
+
"artifact": "PRD",
|
|
1885
|
+
"where": "Bước 6",
|
|
1886
|
+
"scope_source": "UC mới + UC SỞ HỮU mỗi BR/AC bị sửa (kết luận của Bước 3.2)"
|
|
1887
|
+
},
|
|
1888
|
+
{
|
|
1889
|
+
"cmd": "amend-prd",
|
|
1890
|
+
"artifact": "PRD",
|
|
1891
|
+
"where": "Bước 5",
|
|
1892
|
+
"scope_source": "UC SỞ HỮU của mỗi ID mà PO khai tường minh ở Bước 1 (`amend_targets`)"
|
|
1893
|
+
},
|
|
1894
|
+
{
|
|
1895
|
+
"cmd": "review-context",
|
|
1896
|
+
"artifact": "PRD",
|
|
1897
|
+
"where": "Fix Mode Phase 3",
|
|
1898
|
+
"scope_source": "`uc_id` của mọi finding `status: applied` (findings YAML — field bắt buộc)",
|
|
1899
|
+
"emits_neutral_marker": true,
|
|
1900
|
+
"why_emits": "nó là producer DUY NHẤT biết chính xác `check_id` của từng fix vừa áp, nên là producer duy nhất chứng minh được tính trung tính"
|
|
1901
|
+
},
|
|
1902
|
+
{
|
|
1903
|
+
"cmd": "generate-tech-docs",
|
|
1904
|
+
"artifact": "tech-design.md",
|
|
1905
|
+
"where": "Bước 1 (APPEND) + §Sinh",
|
|
1906
|
+
"scope_source": "UC trong `input_features` của batch vừa thêm/sửa"
|
|
1907
|
+
}
|
|
1908
|
+
],
|
|
1909
|
+
"consumers": [
|
|
1910
|
+
{
|
|
1911
|
+
"cmd": "validate-traces",
|
|
1912
|
+
"where": "Step 4 (PRD) · Step 5 (tech-doc)",
|
|
1913
|
+
"use": "phân loại 🟠 DRIFT vs ⓘ STALE_REF theo từng UC"
|
|
1914
|
+
},
|
|
1915
|
+
{
|
|
1916
|
+
"cmd": "generate-bdd",
|
|
1917
|
+
"where": "Version Check",
|
|
1918
|
+
"use": "khuyến nghị Y (cập nhật hẹp) vs F (gen lại toàn bộ)"
|
|
1919
|
+
}
|
|
1920
|
+
]
|
|
1921
|
+
},
|
|
1922
|
+
"spec_edit_detection": {
|
|
1923
|
+
"$comment": [
|
|
1924
|
+
"PHÁT HIỆN SỬA TÀI LIỆU NGOÀI ĐƯỜNG CHÍNH THỨC (G54, nửa sau).",
|
|
1925
|
+
"",
|
|
1926
|
+
"TOÀN BỘ lưới an toàn của framework so NHÃN VERSION, không so NỘI DUNG — không có một",
|
|
1927
|
+
"content hash nào ở đâu. Nên một PRD bị sửa tay mà không bump version là điểm mù TUYỆT",
|
|
1928
|
+
"ĐỐI: validate-traces thấy `PRD version == prd_version` ⇒ sạch · gate-trace thấy report",
|
|
1929
|
+
"khớp sổ ⇒ PASS · require-fresh-audit thấy PR không chạm tag ⇒ không đòi audit. Cả ba",
|
|
1930
|
+
"tầng xanh, và cả ba ĐÚNG theo định nghĩa của chính chúng.",
|
|
1931
|
+
"",
|
|
1932
|
+
"Và G54 không chỉ CHO PHÉP sửa tay — nó ĐẨY người dùng về đó: /generate-prd DỪNG HẲN trên",
|
|
1933
|
+
"file đã có (§Guard: 'Tồn tại → DỪNG. KHÔNG ghi, KHÔNG hỏi Y/N') · /extend-prd chỉ",
|
|
1934
|
+
"add-only · /refine-prd chỉ áp được finding do chính nó tìm ra. Trước /amend-prd, hành",
|
|
1935
|
+
"vi hợp lý duy nhất còn lại LÀ mở file .md ra gõ. Thiết kế tự tạo ra con đường nó không",
|
|
1936
|
+
"canh được.",
|
|
1937
|
+
"",
|
|
1938
|
+
"VÌ SAO KHÔNG DÙNG CONTENT HASH: git đã băm nội dung hộ rồi. Thêm một cột hash vào sổ",
|
|
1939
|
+
"TSV là thêm một thứ ghi-tay-bởi-LLM (đúng lớp lỗi G38 mà lint-trace tồn tại để chống),",
|
|
1940
|
+
"trong khi `git diff` trả lời chính xác cùng câu hỏi và không sai được.",
|
|
1941
|
+
"",
|
|
1942
|
+
"VÌ SAO KHÔNG NẰM TRONG `gate.blocking` — quyết định có chủ ý, không phải bỏ sót:",
|
|
1943
|
+
" 1. `gate.blocking` có nghĩa HẸP là CODE ĐANG HỎNG, và R9(e) tồn tại để giữ ranh giới",
|
|
1944
|
+
" đó. Cờ này nói về SPEC; code có thể đang hoàn toàn đúng.",
|
|
1945
|
+
" 2. Nợ tồn khi mới bật: mọi project đang chạy đều đã có PRD sửa tay. Một cờ chặn mới",
|
|
1946
|
+
" sẽ đỏ khắp nơi ở lần chạy đầu ⇒ người ta TẮT CỔNG ⇒ mất luôn 4 cờ 🔴 thật. Đó",
|
|
1947
|
+
" đúng là thất bại R9(e) được viết ra để chặn, chỉ đến bằng một cửa khác.",
|
|
1948
|
+
" 3. Nó vẫn 🔴 trong REPORT và in mỗi lần chạy — đủ để thấy, không đủ để làm tắt cổng.",
|
|
1949
|
+
"Team nào đã dọn sạch nợ tồn thì tự thêm counter này vào `gate.blocking`; một dòng.",
|
|
1950
|
+
"",
|
|
1951
|
+
"ĐƯỜNG RA TỰ LÀNH — cố ý KHÔNG có lệnh escape riêng: cách sửa đúng là bump version +",
|
|
1952
|
+
"ghi một row changelog (tức chính việc /amend-prd làm hộ). Làm xong thì",
|
|
1953
|
+
"`version != version_at_audit` ⇒ cờ tự tắt, và logic PRD_DRIFT bình thường tiếp quản.",
|
|
1954
|
+
"Thêm một `--accept-edit` sẽ là thêm một đường DÁN NHÃN lên thay đổi chưa ai xem — đúng",
|
|
1955
|
+
"cái sai mà rào của `--realign` tồn tại để chặn."
|
|
1956
|
+
],
|
|
1957
|
+
"flag": "PRD_UNTRACKED_EDIT",
|
|
1958
|
+
"detects": "nội dung file PRD đã đổi kể từ lần audit trước NHƯNG nhãn `Version` không đổi ⇒ có người sửa ngoài /generate-prd · /extend-prd · /amend-prd · /refine-prd · /review-context",
|
|
1959
|
+
"baseline_fields": {
|
|
1960
|
+
"$comment": "validate-traces GHI khối này vào trace-report.json mỗi lần chạy; lần chạy sau ĐỌC nó làm mốc. Thiếu nửa GHI thì cờ không bao giờ bật — R6/R7 chỉ canh được nửa BÁO CÁO (giá trị enum có xuất hiện · counter có trong summary), nên self-check R13 canh nửa này.",
|
|
1961
|
+
"path": "spec_baseline",
|
|
1962
|
+
"keys": [
|
|
1963
|
+
"prd_path",
|
|
1964
|
+
"sha_at_audit",
|
|
1965
|
+
"version_at_audit"
|
|
1966
|
+
]
|
|
1967
|
+
},
|
|
1968
|
+
"evidence": [
|
|
1969
|
+
{
|
|
1970
|
+
"source": "git diff",
|
|
1971
|
+
"cmd": "git -C {specs repo} diff --name-only {sha_at_audit}..HEAD -- {prd_path}",
|
|
1972
|
+
"catches": "sửa đã commit"
|
|
1973
|
+
},
|
|
1974
|
+
{
|
|
1975
|
+
"source": "git status",
|
|
1976
|
+
"cmd": "git -C {specs repo} status --porcelain -- {prd_path}",
|
|
1977
|
+
"catches": "sửa CHƯA commit — ca thường gặp nhất khi PO đang gõ"
|
|
1978
|
+
}
|
|
1979
|
+
],
|
|
1980
|
+
"no_false_positive": "PO sửa VÀ bump version → `version != version_at_audit` → KHÔNG bật cờ. Chỉ đúng ca \"đổi nội dung, giữ nguyên nhãn\" mới bật.",
|
|
1981
|
+
"degraded": "Không phải git repo, hoặc `sha_at_audit` không còn (history bị rewrite) → BỎ QUA check này và in một dòng ⚠️ nói rõ là đang mù, KHÔNG bịa cờ và KHÔNG im lặng.",
|
|
1982
|
+
"written_by": [
|
|
1983
|
+
"validate-traces"
|
|
1984
|
+
],
|
|
1985
|
+
"read_by": [
|
|
1986
|
+
"validate-traces",
|
|
1987
|
+
"sync"
|
|
1988
|
+
],
|
|
1989
|
+
"$read_by_comment": [
|
|
1990
|
+
"`sync` đọc mốc này để trả lời câu KHÁC với câu của diff pull-to-pull (G56).",
|
|
1991
|
+
"Diff `{old_sha}..{new_sha}` trả lời \"đổi gì kể từ lần PULL trước\" — mốc đó RESET mỗi lần",
|
|
1992
|
+
"pull. Pull thứ Hai, thứ Ba, thứ Tư mà không audit lần nào thì đến thứ Năm cái thấy được chỉ",
|
|
1993
|
+
"là delta của MỘT ngày, không phải nợ đã tích. `sha_at_audit` trả lời \"đổi gì kể từ lần",
|
|
1994
|
+
"AUDIT gần nhất\" — con số đó tích luỹ đúng, không bao giờ reset sai."
|
|
1995
|
+
]
|
|
1996
|
+
},
|
|
1997
|
+
"positive_assertion_guards": {
|
|
1998
|
+
"$comment": [
|
|
1999
|
+
"QUYỀN ĐƯỢC KHẲNG ĐỊNH `pass` (G55) — mệnh đề ĐỐI NGẪU của luật G28.",
|
|
2000
|
+
"",
|
|
2001
|
+
"rules/workflow.md §\"Làm mất hiệu lực ≠ ghi đè\" nói: ai làm một giá trị HẾT ĐÚNG thì BẮT",
|
|
2002
|
+
"BUỘC hạ nó xuống. Luật đó đúng và được thực thi tốt (/generate-bdd, /generate-code,",
|
|
2003
|
+
"/fix-bug đều làm). Nhưng nửa còn lại chưa được viết: AI KHẲNG ĐỊNH MỘT GIÁ TRỊ DƯƠNG THÌ",
|
|
2004
|
+
"PHẢI KIỂM RẰNG MÌNH ĐƯỢC PHÉP KHẲNG ĐỊNH.",
|
|
2005
|
+
"",
|
|
2006
|
+
"Thiếu nửa sau nên chuỗi thành: hạ xuống → dựng lại → hạ xuống → dựng lại.",
|
|
2007
|
+
" 1. PO đổi AC → /generate-bdd đặt status=DRIFT và HẠ dev_selftest→not_run, kèm cảnh báo",
|
|
2008
|
+
" \"{n} test của {sc_id} viết cho spec cũ — /dev-gen-test rà lại trước khi chạy\".",
|
|
2009
|
+
" 2. Sáng sau dev chạy /dev-run-test (thói quen bình thường), CHƯA /generate-code, CHƯA",
|
|
2010
|
+
" /dev-gen-test. Test cũ + code cũ ⇒ xanh hết.",
|
|
2011
|
+
" 3. /dev-run-test ghi dev_selftest=pass, dev_selftest_at=HÔM NAY.",
|
|
2012
|
+
"Row giờ mang status=DRIFT + dev_selftest=pass với ngày hôm nay. Lệnh kế tiếp trong vòng",
|
|
2013
|
+
"lặp dev BÌNH THƯỜNG vừa dựng lại đúng cái tín hiệu /generate-bdd hạ xuống.",
|
|
2014
|
+
"",
|
|
2015
|
+
"VÌ SAO `status` KHÔNG TRỰC GIAO Ở ĐÂY: hai file lệnh viết `dev_selftest`/`qc_status`",
|
|
2016
|
+
"\"trực giao với status\". Trực giao về KẾT QUẢ CHẠY thì đúng. Nhưng ô này không mang nghĩa",
|
|
2017
|
+
"\"test đã chạy và xanh\" — nó mang nghĩa \"scenario này đã được nghiệm thu theo spec HIỆN",
|
|
2018
|
+
"TẠI\". Trên row DRIFT, nghĩa thứ nhất đúng và nghĩa thứ hai SAI. `pass` ở đó không phải",
|
|
2019
|
+
"kết quả sai; nó là lời khẳng định sai về điều mà kết quả đó chứng minh.",
|
|
2020
|
+
"",
|
|
2021
|
+
"TIN XẤU LUÔN HỢP LỆ: `fail` VẪN được ghi trên row DRIFT. Đây là guard cho lời khẳng định",
|
|
2022
|
+
"DƯƠNG, không phải lệnh \"bỏ qua kết quả khi DRIFT\". Test đỏ trên row DRIFT vẫn là thông",
|
|
2023
|
+
"tin thật. Chỉ `pass` cần giấy phép.",
|
|
2024
|
+
"",
|
|
2025
|
+
"VÌ SAO CẦN CẢ HAI TẦNG:",
|
|
2026
|
+
" PA-1 (lệnh đọc status trước khi ghi) chặn NGUỒN.",
|
|
2027
|
+
" PA-2 (lint-trace T12) bắt TRẠNG THÁI, bất kể ai ghi — sổ sửa tay, sổ sinh bởi version",
|
|
2028
|
+
" framework cũ, hay một lệnh tương lai quên luật. T12 rẻ, xác định, chạy được trong",
|
|
2029
|
+
" CI mà không cần LLM.",
|
|
2030
|
+
"T1–T8 kiểm HÌNH DẠNG TỪNG Ô (đủ 24 cột, giá trị trong vocabulary, ngày parse được) —",
|
|
2031
|
+
"không rule nào kiểm NHẤT QUÁN GIỮA CÁC Ô. Nên `status=DRIFT` + `dev_selftest=pass` là một",
|
|
2032
|
+
"sổ HOÀN TOÀN HỢP LỆ với cả 11 rule cũ. T12 là rule đầu tiên nhìn nhiều ô cùng lúc.",
|
|
2033
|
+
"",
|
|
2034
|
+
"LỖ ĐÃ BIẾT, chấp nhận có chủ ý: ca \"spec đổi theo hướng THÊM hành vi mới\". Sau khi",
|
|
2035
|
+
"/generate-code bắt kịp, gen_ver=spec_ver ⇒ status=OK; test cũ vẫn PASS (chúng không sai,",
|
|
2036
|
+
"chỉ KHÔNG PHỦ phần mới); test_count>0 nên không có GAP ⇒ bảng xanh trên một hành vi chưa",
|
|
2037
|
+
"test lần nào. Đóng hẳn ca này cần một cột thứ 25 `test_spec_ver` — đổi contract + lint",
|
|
2038
|
+
"binding + backward-compat với mọi sổ 24 cột đang tồn tại. Hoãn có chủ ý; guard này vẫn",
|
|
2039
|
+
"thu hẹp đáng kể vì trong lúc row còn DRIFT thì dev_selftest bị giữ ở not_run, nên dev",
|
|
2040
|
+
"buộc phải làm gì đó và đường đúng là /dev-gen-test."
|
|
2041
|
+
],
|
|
2042
|
+
"lint_rule": "T12",
|
|
2043
|
+
"blocked_when_status": [
|
|
2044
|
+
"DRIFT",
|
|
2045
|
+
"ORPHANED"
|
|
2046
|
+
],
|
|
2047
|
+
"negative_always_written": "`fail` được ghi bình thường trên MỌI status — guard này chỉ chặn giá trị KHẲNG ĐỊNH. Chặn cả `fail` là biến một guard chống-báo-cáo-sai thành một guard che-tin-xấu.",
|
|
2048
|
+
"guards": [
|
|
2049
|
+
{
|
|
2050
|
+
"column": "dev_selftest",
|
|
2051
|
+
"owner": "dev-run-test",
|
|
2052
|
+
"positive_values": [
|
|
2053
|
+
"pass"
|
|
2054
|
+
],
|
|
2055
|
+
"downgrade_to": "not_run",
|
|
2056
|
+
"companion": "dev_selftest_at",
|
|
2057
|
+
"companion_downgrade": "—",
|
|
2058
|
+
"why": "trên row DRIFT, test cũ đang nghiệm thu một hành vi không còn tồn tại; trên row ORPHANED, scenario đã bị xoá khỏi .feature nên không còn gì để nghiệm thu"
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
"column": "qc_status",
|
|
2062
|
+
"owner": "qc-run-test",
|
|
2063
|
+
"positive_values": [
|
|
2064
|
+
"pass"
|
|
2065
|
+
],
|
|
2066
|
+
"downgrade_to": "not_run",
|
|
2067
|
+
"companion": "qc_run_at",
|
|
2068
|
+
"companion_downgrade": "—",
|
|
2069
|
+
"why": "đối xứng hoàn toàn với dev_selftest — `skip` KHÔNG bị chặn vì nó là giá trị trung tính, không phải lời khẳng định"
|
|
2070
|
+
}
|
|
2071
|
+
]
|
|
2072
|
+
},
|
|
2073
|
+
"testid_contract": {
|
|
2074
|
+
"$comment": [
|
|
2075
|
+
"HỢP ĐỒNG TEST-ID FE↔QC — phần được MÁY canh.",
|
|
2076
|
+
"",
|
|
2077
|
+
"Contract gồm hai nửa, ở hai chỗ khác nhau trong CÙNG một tech-doc:",
|
|
2078
|
+
" @trace.testid_attr (header, scope file) → TÊN THUỘC TÍNH, MỘT giá trị cho cả doc",
|
|
2079
|
+
" bảng §4.5.6 (thân, theo nền) → GIÁ TRỊ test-id từng element, N dòng",
|
|
2080
|
+
"Consumer per-UC lọc row của mình qua cột 'Serves SC (UC · SC)'.",
|
|
2081
|
+
"",
|
|
2082
|
+
"VÌ SAO CẦN CANH: trước khối này, bảng §4.5.6 được 3 lệnh ĐỌC (generate-code, qc-run-test,",
|
|
2083
|
+
"qc-design-test) và 2 lệnh GHI (generate-tech-docs, map-testids) — mà 0 nơi kiểm. Luật chống",
|
|
2084
|
+
"giẫm chân giữa hai người ghi là một CÂU VĂN XUÔI ở map-testids Step 5. Đây đúng hình dạng",
|
|
2085
|
+
"đã gặp bốn lần trong loạt GAP: luật ĐÚNG, viết RÕ, và KHÔNG AI CANH (G1 · G28 · G41 · G55).",
|
|
2086
|
+
"",
|
|
2087
|
+
"PHẠM VI NEO VÀO SỰ TỒN TẠI CỦA HỢP ĐỒNG — điều khoản quan trọng nhất của khối này:",
|
|
2088
|
+
"doc không có block §4.5 client thì KHÔNG kiểm gì. Dự án backend-only, hay dự án chưa từng",
|
|
2089
|
+
"chạy /map-testids, phải im lặng hoàn toàn. Hai rule nói 'chỗ nào đã hứa thì phải giữ',",
|
|
2090
|
+
"KHÔNG nói 'mọi chỗ đều phải có hợp đồng'. Thiếu điều khoản này thì mọi dự án đang chạy đỏ",
|
|
2091
|
+
"ngay ngày nâng version, và việc đầu tiên người ta làm là thêm --warn-only vào CI.",
|
|
2092
|
+
"",
|
|
2093
|
+
"KHÔNG vào gate.blocking: đây là nợ cần thấy, không phải 'đang có cái sai' chặn PR.",
|
|
2094
|
+
"Cùng nhóm với TECHDOC_DRIFT / BDD_DRIFT — 13/17 cờ audit hiện tại cũng không chặn."
|
|
2095
|
+
],
|
|
2096
|
+
"artifact": "tech-design.md",
|
|
2097
|
+
"header_field": "@trace.testid_attr",
|
|
2098
|
+
"table_section": "4.5.6",
|
|
2099
|
+
"serves_column": "Serves SC",
|
|
2100
|
+
"lint_rules": [
|
|
2101
|
+
{
|
|
2102
|
+
"rule": "T15",
|
|
2103
|
+
"level": "error",
|
|
2104
|
+
"why": "Row §4.5.6 trỏ tới SC không tồn tại trong .feature. Consumer per-UC LỌC theo cột 'Serves SC' — trỏ vào SC đã bị gộp/xoá thì không khớp row nào, QC tưởng element không có test-id rồi đi dò DOM. Đây là phép so khớp chuỗi, không có chỗ cho suy luận, nên ERROR."
|
|
2105
|
+
},
|
|
2106
|
+
{
|
|
2107
|
+
"rule": "T16",
|
|
2108
|
+
"level": "warn+error",
|
|
2109
|
+
"why": "Doc có §4.5 client mà header KHÔNG CÓ DÒNG @trace.testid_attr → WARN (G86): đó là doc LEGACY, sinh trước khi field vào template — trạng thái HỢP LỆ trong quy trình, y như placeholder. Lập luận giữ `error` ('QC đoán theo nền ⇒ trượt 100% locator TRONG IM LẶNG') đã HẾT ĐÚNG: qc-run-test và generate-code đều 'Cảnh báo mềm, KHÔNG im lặng hardcode'. Giữ error là dựng cổng thứ hai cho chuyện đã có người canh — và cổng đó CHẶN NHẦM NGƯỜI (30 doc của 2 domain khác chặn /validate-traces --prd FEAT-01-1). Cùng lập luận đã dùng cho T14. | Dòng CÓ MẶT mà giá trị RỖNG → vẫn ERROR: đó là 'ai đó xoá' khỏi một hợp đồng ĐÃ CHỐT. Dòng-không-tồn-tại vs dòng-rỗng là chỗ DUY NHẤT máy phân biệt được legacy với bị-xoá. | Còn placeholder → WARN."
|
|
2110
|
+
},
|
|
2111
|
+
{
|
|
2112
|
+
"rule": "T17",
|
|
2113
|
+
"level": "warn",
|
|
2114
|
+
"needs": "--code",
|
|
2115
|
+
"why": "Id đã khai ở §4.5.6 mà KHÔNG có trong code: FE chưa gắn, gắn sai giá trị, hoặc element đã đổi lúc implement. QC sẽ trượt locator đúng ở những id đó. WARN chứ không ERROR vì id đoán từ thiết kế không sống sót 100% — dev có thể gộp/tách element lúc implement, và đó là nợ cần thấy chứ không phải cái sai chặn người."
|
|
2116
|
+
},
|
|
2117
|
+
{
|
|
2118
|
+
"rule": "T18",
|
|
2119
|
+
"level": "warn",
|
|
2120
|
+
"needs": "--code",
|
|
2121
|
+
"why": "Id nằm trong code mà không có trong §4.5.6 nào: ai đó gắn ngoài hợp đồng — thường là /generate-code chạy khi bảng rỗng (người dùng chọn 'vẫn sinh với id TẠM'), hoặc sửa tay. Đây là lưới bắt phía sau cho quyết định đó: hợp đồng không còn đủ, và QC không biết những id này tồn tại. Chính vì có T18 mà /generate-code được phép hỏi rồi đi tiếp thay vì chặn cứng."
|
|
2122
|
+
}
|
|
2123
|
+
],
|
|
2124
|
+
"scope_flag": {
|
|
2125
|
+
"flag": "--scope-prd",
|
|
2126
|
+
"applies_to": [
|
|
2127
|
+
"T15",
|
|
2128
|
+
"T16",
|
|
2129
|
+
"T19",
|
|
2130
|
+
"T20"
|
|
2131
|
+
],
|
|
2132
|
+
"never_applies_to": "T1–T14 (rule SỔ)",
|
|
2133
|
+
"$comment": [
|
|
2134
|
+
"G87 — rule TECH-DOC thu hẹp được theo PRD; rule SỔ thì KHÔNG.",
|
|
2135
|
+
"",
|
|
2136
|
+
"validate-traces:66 khai cố ý \"lint luôn chạy toàn bộ — sổ hỏng ở domain khác vẫn là sổ hỏng\".",
|
|
2137
|
+
"ĐÚNG cho T1-T14: .tsv không regenerate được, và Step 3/6 của lệnh đó GHI NGƯỢC vào sổ.",
|
|
2138
|
+
"T15/T16/T19/T20 canh TECH-DOC. Lý do kia không nối sang được, mà exit 1 thì chung một cửa —",
|
|
2139
|
+
"nên lệnh CÓ SCOPE bị chặn bởi lỗi ở PRD NGOÀI SCOPE. Đã xảy ra thật.",
|
|
2140
|
+
"",
|
|
2141
|
+
"KHÔNG thu hẹp bằng --specs hẹp lại: lintTestidContract cần {domain}/{prd-slug} để tìm bdd/,",
|
|
2142
|
+
"nên --specs trỏ thẳng feature-package làm parts.length<3 ⇒ continue ⇒ BỎ QUA IM LẶNG và báo",
|
|
2143
|
+
"SẠCH trên tech-doc chưa từng được kiểm. Cách lách hiển nhiên nhất cho ra XANH GIẢ."
|
|
2144
|
+
]
|
|
2145
|
+
}
|
|
2146
|
+
},
|
|
2147
|
+
"artifact_writers": {
|
|
2148
|
+
"$comment": [
|
|
2149
|
+
"AI GHI ARTIFACT NÀO, VÀ ARTIFACT ĐÓ CÓ PHẦN NGƯỜI NHẬP TAY KHÔNG (G74 · R18).",
|
|
2150
|
+
"",
|
|
2151
|
+
"VÌ SAO KHỐI NÀY TỒN TẠI — ĐẢO CHIỀU MỘT ALLOWLIST:",
|
|
2152
|
+
"gate.checkpoint_levels là allowlist với mặc định `normal` (mức LỎNG NHẤT). Lệnh không khai",
|
|
2153
|
+
"gì thì rơi vào đó. R11 duyệt TỪ SCHEMA RA FILE — nó chỉ kiểm lệnh ĐÃ được liệt kê, nên lệnh",
|
|
2154
|
+
"CHƯA khai thì không vòng lặp nào chạm tới. Schema tự thú điểm yếu đó ngay ở $comment của",
|
|
2155
|
+
"checkpoint_levels: 'thêm lệnh mới mà quên thêm vào đó thì lại sai lần nữa'. Nó đã sai đúng",
|
|
2156
|
+
"như vậy BỐN lần: G67 (đã sửa) · G77 · G78 · G79.",
|
|
2157
|
+
"",
|
|
2158
|
+
"R18 duyệt CHIỀU NGƯỢC LẠI: mọi lệnh trong `enrolled` phải khai đủ, và khai",
|
|
2159
|
+
"has_human_content:true thì BẮT BUỘC nằm trong checkpoint_levels.hard. Quên = BUILD ĐỎ,",
|
|
2160
|
+
"thay vì quên = mở cửa.",
|
|
2161
|
+
"",
|
|
2162
|
+
"`why` LÀ BẮT BUỘC CẢ KHI has_human_content:false — đó chính là G79. /qc-plan và /qc-review",
|
|
2163
|
+
"ghi đè AN TOÀN, nhưng không ai khai là an toàn, nên một ngoại lệ CÓ CHỦ Ý trông y hệt một chỗ",
|
|
2164
|
+
"sót và sẽ bị copy đi. Bắt khai `why` biến im lặng thành một khẳng định KIỂM CHỨNG ĐƯỢC.",
|
|
2165
|
+
"",
|
|
2166
|
+
"PHẠM VI CÓ CHỦ Ý — `enrolled` hiện chỉ phủ 6 lệnh QC (phạm vi đợt rà GAPS-v5). 27 lệnh còn",
|
|
2167
|
+
"lại nằm ở `pending_enrollment`: nợ được KHAI RA, không phải nợ vô hình. R18 không ép chúng,",
|
|
2168
|
+
"nhưng danh sách đó phải RỖNG DẦN — và nó nằm trong schema nên không ai quên được nó tồn tại.",
|
|
2169
|
+
"Khai một phạm vi hẹp và nói rõ là hẹp thì trung thực hơn là khai đầy đủ mà chưa rà."
|
|
2170
|
+
],
|
|
2171
|
+
"enrolled": {
|
|
2172
|
+
"qc-analyze": {
|
|
2173
|
+
"writes": [
|
|
2174
|
+
"DOC_GAP.md",
|
|
2175
|
+
"REQUIREMENT_ANALYSIS.md",
|
|
2176
|
+
"{refinement_dir}/{TICKET-ID}-qa-findings.yaml"
|
|
2177
|
+
],
|
|
2178
|
+
"has_human_content": true,
|
|
2179
|
+
"why": "PO điền TAY cột `Trạng thái` (Open/Answered) và cột `Câu trả lời` của DOC_GAP.md — không sinh lại được. Mã GAP-UC{N}-{nnn} còn bị .Test.md tham chiếu qua 🚫 Block."
|
|
2180
|
+
},
|
|
2181
|
+
"qc-run-test": {
|
|
2182
|
+
"writes": [
|
|
2183
|
+
"test Python pytest-playwright",
|
|
2184
|
+
"Page Object"
|
|
2185
|
+
],
|
|
2186
|
+
"has_human_content": true,
|
|
2187
|
+
"why": "QC SỬA TAY chính các file này — §Phân loại FAIL khai tường minh: `script-bug` ⇒ 'QC tự sửa. Không mở bug'. Sinh lại là xoá công sửa lỗi, đúng lúc người ta chạy lại để kiểm bản sửa."
|
|
2188
|
+
},
|
|
2189
|
+
"qc-design-test": {
|
|
2190
|
+
"writes": [
|
|
2191
|
+
"test-cases/*.Test.md"
|
|
2192
|
+
],
|
|
2193
|
+
"has_human_content": true,
|
|
2194
|
+
"why": "File đi qua cổng HITL /qc-review: `Status` đổi sau review, `Expected Result` sửa theo finding, dấu 🚫 Block gỡ bằng tay — đều là kết luận của NGƯỜI, không suy lại từ spec. Và REVIEW_<FEATURE>.md đang trỏ vào số TC_<FEATURE>_NNN."
|
|
2195
|
+
},
|
|
2196
|
+
"qc-plan": {
|
|
2197
|
+
"writes": [
|
|
2198
|
+
"TEST_PLAN.md"
|
|
2199
|
+
],
|
|
2200
|
+
"has_human_content": false,
|
|
2201
|
+
"why": "questions-for-dev là danh sách GỬI ĐI; câu trả lời quay về qua DOC_GAP.md hoặc kênh chat, không ai điền ngược vào file này. Stamp phiên bản và cột Ready/Blocked đều do lệnh tự tính. KHAI LẠI NẾU về sau có ai điền tay vào đây."
|
|
2202
|
+
},
|
|
2203
|
+
"qc-review": {
|
|
2204
|
+
"writes": [
|
|
2205
|
+
"test-cases/REVIEW_<FEATURE>.md"
|
|
2206
|
+
],
|
|
2207
|
+
"has_human_content": false,
|
|
2208
|
+
"why": "Là BIÊN BẢN của một lần soát. Sinh lại = soát lại, đúng bản chất của nó — không có trạng thái nào tích luỹ qua các lần chạy."
|
|
2209
|
+
},
|
|
2210
|
+
"qc-report": {
|
|
2211
|
+
"writes": [
|
|
2212
|
+
"reports/<feature>/report.html",
|
|
2213
|
+
"test-results/<nodeid>/trace.zip"
|
|
2214
|
+
],
|
|
2215
|
+
"has_human_content": false,
|
|
2216
|
+
"why": "Sinh hoàn toàn từ lần chạy gần nhất (pytest-html + Playwright Trace). Không có ô nào cho người điền."
|
|
2217
|
+
},
|
|
2218
|
+
"map-testids": {
|
|
2219
|
+
"writes": [
|
|
2220
|
+
"§4.5.6 Test Selectors (tech-doc gộp)",
|
|
2221
|
+
"@trace.testid_attr (header)",
|
|
2222
|
+
"figma-components catalog — Test-ID Forwarding",
|
|
2223
|
+
"usage site FE (--from-code)"
|
|
2224
|
+
],
|
|
2225
|
+
"has_human_content": true,
|
|
2226
|
+
"why": "§4.5.6 là HỢP ĐỒNG do SA viết tay — 28/28 tech-doc thật dùng quy ước riêng (uc{n}-z2-region, ô đa-giá-trị) mà lệnh này KHÔNG tái tạo được (quy ước của nó: {uc-lower}-{screen}-{element}-{type}). Ghi đè là đổi hợp đồng đang được cả FE lẫn QC bám vào, mà không ai yêu cầu."
|
|
2227
|
+
},
|
|
2228
|
+
"dev-gen-test": {
|
|
2229
|
+
"writes": [
|
|
2230
|
+
"file unit/integration/E2E test theo module dev",
|
|
2231
|
+
"sổ trace: test_count · test_classes · dev_selftest"
|
|
2232
|
+
],
|
|
2233
|
+
"has_human_content": true,
|
|
2234
|
+
"why": "Dev SỬA TAY chính các file test này — /dev-run-test:260 nói thẳng: \"Test fail → /fix-bug (bug thật) hoặc FIX TEST (sai expectation)\", và :137 \"Thêm mock; kiểm tra test fixture\". Cùng khuôn G77 ở lane QC, khác lane."
|
|
2235
|
+
}
|
|
2236
|
+
},
|
|
2237
|
+
"pending_enrollment": {
|
|
2238
|
+
"$comment": "Lệnh CÓ ghi file nhưng CHƯA rà xem có phần người nhập tay không. R18 không ép, nhưng danh sách này phải rỗng dần. Nợ được KHAI, không phải nợ vô hình.",
|
|
2239
|
+
"cmds": [
|
|
2240
|
+
"generate-prd",
|
|
2241
|
+
"extend-prd",
|
|
2242
|
+
"amend-prd",
|
|
2243
|
+
"refine-prd",
|
|
2244
|
+
"generate-bdd",
|
|
2245
|
+
"generate-tech-docs",
|
|
2246
|
+
"generate-design-spec",
|
|
2247
|
+
"generate-architecture",
|
|
2248
|
+
"generate-code",
|
|
2249
|
+
"review-context",
|
|
2250
|
+
"review-tech-docs",
|
|
2251
|
+
"review-code",
|
|
2252
|
+
"fix-bug",
|
|
2253
|
+
"report-bug",
|
|
2254
|
+
"propose-scenario",
|
|
2255
|
+
"define-product",
|
|
2256
|
+
"setup-ai-first",
|
|
2257
|
+
"generate-spec-manifest",
|
|
2258
|
+
"validate-traces",
|
|
2259
|
+
"sync",
|
|
2260
|
+
"learn",
|
|
2261
|
+
"update-framework",
|
|
2262
|
+
"dev-run-test",
|
|
2263
|
+
"dev-smoke-test",
|
|
2264
|
+
"debug"
|
|
2265
|
+
]
|
|
2266
|
+
}
|
|
2267
|
+
},
|
|
2268
|
+
"testid_fourth_leg": {
|
|
2269
|
+
"$comment": [
|
|
2270
|
+
"CHÂN THỨ TƯ CỦA HỢP ĐỒNG TEST-ID: §4.5.6 ↔ *.Test.md (G64).",
|
|
2271
|
+
"",
|
|
2272
|
+
"testid_contract canh BA chân — ↔ .feature (T15) · ↔ header attr (T16) · ↔ code (T17/T18).",
|
|
2273
|
+
"Chân thứ tư không ai canh, và nó là chân DUY NHẤT mà giá trị id bị CHÉP CỨNG vào một artifact",
|
|
2274
|
+
"BỀN rồi nằm lại:",
|
|
2275
|
+
" generate-code → bake vào code → T17/T18 canh",
|
|
2276
|
+
" qc-run-test → dựng locator LÚC CHẠY → đọc bảng tươi, tự cứu",
|
|
2277
|
+
" qc-design-test → chép vào .Test.md → KHÔNG AI CANH ← đây",
|
|
2278
|
+
"",
|
|
2279
|
+
"KIỂU HỎNG LÀ 'NÓI DỐI', KHÔNG PHẢI 'IM LẶNG'. Lỗi CÓ hiện ra, nhưng ĐỘI LỐT thứ khác:",
|
|
2280
|
+
"testid_contract đã ghi đúng chữ — 'test đỏ element not found TRÔNG Y HỆT bug sản phẩm'. Nên",
|
|
2281
|
+
"/qc-report phân loại product-gap rồi in một /report-bug sẵn-chạy, và một lỗi hợp đồng NỘI BỘ",
|
|
2282
|
+
"đi ra khỏi đội QC thành phiếu lỗi gửi PO.",
|
|
2283
|
+
"",
|
|
2284
|
+
"ĐẶT Ở TRẠM, KHÔNG Ở lint-trace. lint-trace quét theo cờ đường dẫn (--trace/--specs/--code) và",
|
|
2285
|
+
"KHÔNG có --qc; thêm cờ thì khả thi (khác hẳn /validate-traces ở G63 — lệnh đó tự phân giải path",
|
|
2286
|
+
"và không thể với tới), nhưng chỉ phủ khi người vận hành nhớ trỏ CẢ --specs LẪN --qc. Trạm 4-5",
|
|
2287
|
+
"thì LUÔN đọc cả hai file, nên phủ 100% đường đi thật. Một rule lint T19 vẫn đáng làm sau, như",
|
|
2288
|
+
"lớp CI — 'canh contract ≠ canh dữ liệu'.",
|
|
2289
|
+
"",
|
|
2290
|
+
"MỘT CHIỀU, KHÔNG HAI. Chiều ngược (§4.5.6 có id mà không TC nào nhắc) KHÔNG kiểm: không phải",
|
|
2291
|
+
"element nào cũng cần một bước TC, nên kiểm chiều đó là ỒN. Đúng bất đối xứng T17/T18."
|
|
2292
|
+
],
|
|
2293
|
+
"direction": "test_md_to_table",
|
|
2294
|
+
"lint_rule": {
|
|
2295
|
+
"rule": "T19",
|
|
2296
|
+
"level": "warn",
|
|
2297
|
+
"needs": "--qc",
|
|
2298
|
+
"why": "LỚP CI cho chân thứ tư (G76). Guard ở /qc-review + /qc-run-test phủ 100% đường đi thật nhưng do LLM thực thi — nó không chặn được TRƯỚC khi merge. T19 nông hơn (chỉ so chuỗi) nhưng chạy trong CI. rules/workflow.md: 'Canh contract ≠ canh dữ liệu. Cần CẢ HAI' — đúng cặp self-check ↔ lint-trace. Bất đối xứng 3/4 (ba chân có lint, một chân không) là hình dạng G33: người đọc contract thấy bốn chân 'đã được canh' mà không phân biệt được chân nào chặn được ở CI.",
|
|
2299
|
+
"skip_clauses": [
|
|
2300
|
+
"Thiếu --qc → BỎ QUA CÓ TIẾNG. Không default: gốc artifact QC không đoán được (qc_dir là path QC duy nhất không remap theo spec_source), và 'quét sai chỗ còn tệ hơn không quét'.",
|
|
2301
|
+
"Không có §4.5 client → im lặng HOÀN TOÀN. Điều khoản phạm vi của testid_contract; thiếu nó thì mọi dự án backend-only đỏ ngay ngày nâng version và việc đầu tiên người ta làm là thêm --warn-only vào CI.",
|
|
2302
|
+
"--qc trỏ thư mục không có *.Test.md → BỎ QUA CÓ TIẾNG. Trỏ nhầm đường mà im lặng là xanh giả."
|
|
2303
|
+
]
|
|
2304
|
+
},
|
|
2305
|
+
"checked_by": [
|
|
2306
|
+
{
|
|
2307
|
+
"cmd": "qc-review",
|
|
2308
|
+
"level": "warn"
|
|
2309
|
+
},
|
|
2310
|
+
{
|
|
2311
|
+
"cmd": "qc-run-test",
|
|
2312
|
+
"level": "warn",
|
|
2313
|
+
"$note": "warn, KHÔNG chặn `pass` như qc_artifact_stamp. Id sai làm test ĐỎ, không làm test xanh giả — nên nó không thuộc lớp 'báo cáo sai'. Chặn ở đây là chặn nhầm loại."
|
|
2314
|
+
}
|
|
2315
|
+
],
|
|
2316
|
+
"filter": "Lọc row §4.5.6 theo cột 'Serves SC' khớp SC của UC này — id phục vụ UC khác không tính là 'lạ'.",
|
|
2317
|
+
"scope_guard": "Không có block §4.5 client (dự án backend-only, hoặc chưa chạy /map-testids) → IM LẶNG HOÀN TOÀN. Cùng điều khoản phạm vi với testid_contract."
|
|
2318
|
+
},
|
|
2319
|
+
"qc_artifact_stamp": {
|
|
2320
|
+
"$comment": [
|
|
2321
|
+
"ARTIFACT QC PHẢI GHI MÌNH SINH RA TỪ BẢN NÀO — và trạm sau phải ĐỌC cái ghi đó (G63).",
|
|
2322
|
+
"",
|
|
2323
|
+
"VÌ SAO CẦN: /generate-bdd hạ qc_status → not_run khi spec đổi, rất đúng luật. Nhưng đó là",
|
|
2324
|
+
"nửa 'KẾT QUẢ CHẠY hết hiệu lực'. Nửa còn thiếu là 'TÀI LIỆU THIẾT KẾ TEST hết khớp' — và",
|
|
2325
|
+
"hai nửa dẫn tới HAI VIỆC KHÁC NHAU:",
|
|
2326
|
+
" qc_status = not_run ⇒ CHẠY LẠI (/qc-run-test)",
|
|
2327
|
+
" stamp lệch ⇒ VIẾT LẠI (/qc-design-test)",
|
|
2328
|
+
"Thiếu nửa sau thì người ta thấy not_run và chạy lại một bộ TC lỗi thời — ra `pass`, và `pass`",
|
|
2329
|
+
"đó HỢP LỆ theo mọi phép kiểm hiện có. rules/workflow.md: '`pass` … mang nghĩa scenario này",
|
|
2330
|
+
"đã được nghiệm thu theo spec HIỆN TẠI'.",
|
|
2331
|
+
"",
|
|
2332
|
+
"VÌ SAO KHÔNG ĐẶT Ở /validate-traces — ĐIỀU KHOẢN QUAN TRỌNG NHẤT CỦA KHỐI NÀY:",
|
|
2333
|
+
"qc_dir là path QC DUY NHẤT không được remap khi setup.spec_source được đặt (specs_dir,",
|
|
2334
|
+
"tech_docs_dir, domain_knowledge_dir, trace_dir đều remap; qc_dir ở lại 'docs' của repo QC).",
|
|
2335
|
+
"Nên ở chế độ umbrella — trace-mirror.md gọi là 'trường hợp phổ biến' — sổ trace và artifact",
|
|
2336
|
+
"QC nằm ở HAI REPO KHÁC NHAU, và /validate-traces KHÔNG với tới artifact QC. Phép kiểm phải",
|
|
2337
|
+
"nằm ở chính các trạm QC: chúng đã đọc cả artifact lẫn .feature, nên không phải vượt repo.",
|
|
2338
|
+
"",
|
|
2339
|
+
"VÌ SAO STAMP MÀ KHÔNG CÓ NGƯỜI ĐỌC THÌ VÔ NGHĨA: DOC_GAP.template.md ĐÃ CÓ cột 'Phiên bản'",
|
|
2340
|
+
"trong bảng 'Tài liệu đầu vào đã đọc'. Nó được điền mỗi lần chạy. 0 CONSUMER. Đó là bài học",
|
|
2341
|
+
"buoc/1-02 §B5: 'một con số trong báo cáo KHÔNG chứng minh có phép đo'. Thêm stamp mà không",
|
|
2342
|
+
"thêm checker trong CÙNG một bản sửa là nhân bệnh đó lên bốn.",
|
|
2343
|
+
"",
|
|
2344
|
+
"NHÃN VERSION, KHÔNG PHẢI BĂM NỘI DUNG. rules/workflow.md tự nêu điểm mù: 'mọi drift detector",
|
|
2345
|
+
"so NHÃN VERSION, không so NỘI DUNG'. Framework đã chọn chữa bằng cờ PRD_UNTRACKED_EDIT",
|
|
2346
|
+
"(git diff), không bằng hash — '0 content hash trong toàn bộ codebase'. G63 đi cùng lựa chọn",
|
|
2347
|
+
"đã có, không mở mặt trận thứ hai."
|
|
2348
|
+
],
|
|
2349
|
+
"stamp_marker": "Nguồn & phiên bản",
|
|
2350
|
+
"fields": {
|
|
2351
|
+
"prd_version": {
|
|
2352
|
+
"source": "| **Version** | của bảng metadata đầu PRD",
|
|
2353
|
+
"probe": "\\|\\s*\\*\\*Version\\*\\*\\s*\\|",
|
|
2354
|
+
"artifact": "prd"
|
|
2355
|
+
},
|
|
2356
|
+
"bdd_version": {
|
|
2357
|
+
"source": "@trace.bdd_version của header .feature — GHI THEO TỪNG UC, không một số cho cả file",
|
|
2358
|
+
"probe": "@trace\\.bdd_version\\s*:",
|
|
2359
|
+
"artifact": "feature",
|
|
2360
|
+
"$comment": "G85 — TRƯỚC ĐÓ khai là \"| **Version** | của header .feature\", và đó là KHÔNG THỂ ĐÚNG: .feature là GHERKIN, header của nó là khối comment # @trace.*, không có bảng Markdown nào. Đo thật: 0/278 file có dạng cũ, 276/278 có @trace.bdd_version. Mô tả cũ chép từ khuôn PRD — đúng cho PRD (Markdown có bảng), sai cho Gherkin. Bài học: một khuôn cho N nguồn chỉ đúng khi N nguồn cùng ĐỊNH DẠNG; \"đều có metadata đầu file\" KHÔNG đủ."
|
|
2361
|
+
},
|
|
2362
|
+
"tech_doc_revision": {
|
|
2363
|
+
"source": "@trace.revision của header tech-doc gộp",
|
|
2364
|
+
"probe": "@trace\\.revision\\s*:",
|
|
2365
|
+
"artifact": "tech-design"
|
|
2366
|
+
},
|
|
2367
|
+
"design_spec_version": {
|
|
2368
|
+
"source": "| **Version** | của bảng metadata đầu design-spec; \"—\" khi không có design-spec",
|
|
2369
|
+
"probe": "\\|\\s*\\*\\*Version\\*\\*\\s*\\|",
|
|
2370
|
+
"artifact": "design-spec"
|
|
2371
|
+
},
|
|
2372
|
+
"testid_attr": {
|
|
2373
|
+
"source": "@trace.testid_attr của header tech-doc — chỉ .Test.md",
|
|
2374
|
+
"probe": "@trace\\.testid_attr\\s*:",
|
|
2375
|
+
"artifact": "tech-design",
|
|
2376
|
+
"filled_by": "map-testids",
|
|
2377
|
+
"$comment": [
|
|
2378
|
+
"filled_by — trường này do MỘT LỆNH KHÁC điền sau, không phải phần bắt buộc của artifact.",
|
|
2379
|
+
"Nên \"0/44 file có\" nghĩa là /map-testids CHƯA CHẠY (T16 đã kêu đúng 30 lần), KHÔNG phải mô tả sai.",
|
|
2380
|
+
"Thiếu phân biệt này thì T20 báo oan ngay lần chạy đầu trên mọi dự án chưa chạy map-testids —",
|
|
2381
|
+
"và một rule báo oan là một rule bị tắt."
|
|
2382
|
+
]
|
|
2383
|
+
}
|
|
2384
|
+
},
|
|
2385
|
+
"artifacts": [
|
|
2386
|
+
{
|
|
2387
|
+
"file": "REQUIREMENT_ANALYSIS.md",
|
|
2388
|
+
"written_by": "qc-analyze",
|
|
2389
|
+
"stamps": [
|
|
2390
|
+
"prd_version",
|
|
2391
|
+
"bdd_version",
|
|
2392
|
+
"tech_doc_revision",
|
|
2393
|
+
"design_spec_version"
|
|
2394
|
+
]
|
|
2395
|
+
},
|
|
2396
|
+
{
|
|
2397
|
+
"file": "DOC_GAP.md",
|
|
2398
|
+
"written_by": "qc-analyze",
|
|
2399
|
+
"stamps": [
|
|
2400
|
+
"prd_version",
|
|
2401
|
+
"bdd_version",
|
|
2402
|
+
"tech_doc_revision",
|
|
2403
|
+
"design_spec_version"
|
|
2404
|
+
]
|
|
2405
|
+
},
|
|
2406
|
+
{
|
|
2407
|
+
"file": "TEST_PLAN.md",
|
|
2408
|
+
"written_by": "qc-plan",
|
|
2409
|
+
"stamps": [
|
|
2410
|
+
"inherited"
|
|
2411
|
+
],
|
|
2412
|
+
"$note": "qc-plan KHÔNG đọc spec trực tiếp — nó đọc output trạm 1. Nên nó CHÉP LẠI stamp của DOC_GAP, không tự đi lấy. Tự lấy là tạo hai nguồn cho một số rồi chúng lệch nhau."
|
|
2413
|
+
},
|
|
2414
|
+
{
|
|
2415
|
+
"file": "test-cases/*.Test.md",
|
|
2416
|
+
"written_by": "qc-design-test",
|
|
2417
|
+
"stamps": [
|
|
2418
|
+
"bdd_version",
|
|
2419
|
+
"tech_doc_revision",
|
|
2420
|
+
"testid_attr"
|
|
2421
|
+
]
|
|
2422
|
+
}
|
|
2423
|
+
],
|
|
2424
|
+
"checked_by": [
|
|
2425
|
+
{
|
|
2426
|
+
"cmd": "qc-plan",
|
|
2427
|
+
"checks": [
|
|
2428
|
+
"REQUIREMENT_ANALYSIS.md",
|
|
2429
|
+
"DOC_GAP.md"
|
|
2430
|
+
],
|
|
2431
|
+
"on_stale": "warn"
|
|
2432
|
+
},
|
|
2433
|
+
{
|
|
2434
|
+
"cmd": "qc-design-test",
|
|
2435
|
+
"checks": [
|
|
2436
|
+
"REQUIREMENT_ANALYSIS.md",
|
|
2437
|
+
"DOC_GAP.md",
|
|
2438
|
+
"TEST_PLAN.md"
|
|
2439
|
+
],
|
|
2440
|
+
"on_stale": "warn"
|
|
2441
|
+
},
|
|
2442
|
+
{
|
|
2443
|
+
"cmd": "qc-review",
|
|
2444
|
+
"checks": [
|
|
2445
|
+
"test-cases/*.Test.md"
|
|
2446
|
+
],
|
|
2447
|
+
"on_stale": "warn"
|
|
2448
|
+
},
|
|
2449
|
+
{
|
|
2450
|
+
"cmd": "qc-run-test",
|
|
2451
|
+
"checks": [
|
|
2452
|
+
"test-cases/*.Test.md"
|
|
2453
|
+
],
|
|
2454
|
+
"on_stale": "block_positive_assertion",
|
|
2455
|
+
"$note": "KHÔNG chặn việc chạy. Chặn việc GHI `pass`: test xanh trên TC lỗi thời → qc_status = not_run. Nhập vào cơ chế positive_assertion_guards + lint T12 đã có (G55) — không phát minh cơ chế mới. `fail` VẪN ghi bình thường: đây là guard chống BÁO CÁO SAI, không phải guard CHE TIN XẤU."
|
|
2456
|
+
}
|
|
2457
|
+
],
|
|
2458
|
+
"severity_rationale": {
|
|
2459
|
+
"warn": "Trạm 2-3 cùng họ TECHDOC_DRIFT / BDD_DRIFT — 13/17 cờ audit không chặn. Thiết kế TC trên bản hơi cũ vẫn ra sản phẩm dùng được; chặn ở đây là ồn.",
|
|
2460
|
+
"block_positive_assertion": "Trạm 5 thuộc lớp BÁO CÁO SAI: ghi `pass` từ TC lỗi thời là khẳng định 'đã nghiệm thu theo spec hiện tại' cho một thứ chưa từng được kiểm theo spec hiện tại."
|
|
2461
|
+
},
|
|
2462
|
+
"backward_compat": {
|
|
2463
|
+
"no_stamp_found": "warn_missing_not_stale",
|
|
2464
|
+
"$comment": [
|
|
2465
|
+
"Artifact sinh TRƯỚC khi có khối này thì KHÔNG có stamp. Phải báo 'chưa có stamp — chạy",
|
|
2466
|
+
"lại để đóng dấu', KHÔNG báo 'lệch'. Cùng điều khoản với testid_contract: 'doc không có",
|
|
2467
|
+
"block §4.5 client thì KHÔNG kiểm gì… thiếu điều khoản này thì mọi dự án đang chạy đỏ ngay",
|
|
2468
|
+
"ngày nâng version, và việc đầu tiên người ta làm là thêm --warn-only vào CI'."
|
|
2469
|
+
]
|
|
2470
|
+
},
|
|
2471
|
+
"per_uc_rule": {
|
|
2472
|
+
"$comment": [
|
|
2473
|
+
"bdd_version GHI THEO TỪNG UC. DOC_GAP.md và REQUIREMENT_ANALYSIS.md phủ CẢ PRD, mà mỗi UC",
|
|
2474
|
+
"là một file .feature riêng với version riêng — một số duy nhất cho cả file sẽ SAI cho n-1 UC.",
|
|
2475
|
+
"Và phép so cũng theo từng UC: bump bdd_version của UC2 thì /qc-design-test {UC1} phải IM LẶNG.",
|
|
2476
|
+
"Báo động oan ở đây đắt hơn bình thường vì trạm 3 chạy per-UC, nhiều lần cho mỗi PRD."
|
|
2477
|
+
]
|
|
2478
|
+
},
|
|
2479
|
+
"missing_source": {
|
|
2480
|
+
"rule": "ghi \"—\" VÀ in một dòng ⚠️ — không bỏ trống, không đoán",
|
|
2481
|
+
"$comment": [
|
|
2482
|
+
"Đo thật: 2/278 .feature thiếu @trace.bdd_version. qc-stamp trước đó KHÔNG có ca này.",
|
|
2483
|
+
"Cùng khuôn đã dùng cho @trace.testid_attr: \"Không đọc được → ghi — (thiếu …), ĐỪNG bỏ trống,",
|
|
2484
|
+
"ĐỪNG tự đoán\". Bỏ trống im lặng thì \"không lấy được\" trông y hệt \"artifact cũ chưa có stamp\",",
|
|
2485
|
+
"mà backward_compat bảo ĐỪNG báo lệch ở ca đó — điều khoản tương thích ngược sẽ NUỐT LUÔN lỗi."
|
|
2486
|
+
]
|
|
2487
|
+
},
|
|
2488
|
+
"lint_rule": {
|
|
2489
|
+
"rule": "T20",
|
|
2490
|
+
"level": "warn",
|
|
2491
|
+
"needs": "--specs",
|
|
2492
|
+
"why": "G85 — mọi fields.*.probe phải TÌM ĐƯỢC trong ít nhất một artifact thật. Mô tả \"lấy X từ Y\" đi qua mọi phép kiểm vì chưa ai đi lấy thử: kiểm chỉ dẫn CÓ MẶT khác kiểm nó DÙNG ĐƯỢC. Rule này phải đỏ trên mô tả CŨ của bdd_version — bắt được lỗi ĐÃ BIẾT, không chỉ lỗi tương lai."
|
|
2493
|
+
}
|
|
2494
|
+
},
|
|
2495
|
+
"strict_use_check": {
|
|
2496
|
+
"$comment": [
|
|
2497
|
+
"R3 CANH 'CÓ NHẮC TÊN', KHÔNG CANH 'CÓ DÙNG'. Khối này siết đúng những field mà trả lời",
|
|
2498
|
+
"sai gây hại IM LẶNG — và chỉ những field đó.",
|
|
2499
|
+
"",
|
|
2500
|
+
"R3 kiểm lời khai producer/consumer bằng cách tìm tên field trong file actor. Thấy → ✅.",
|
|
2501
|
+
"Nhưng một file có thể chứa tên field vì nhiều lý do KHÔNG PHẢI 'đang dùng nó':",
|
|
2502
|
+
" 1. câu tuyên bố CỐ Ý BỎ QUA — G55: /dev-run-test viết 'dev_selftest trực giao với",
|
|
2503
|
+
" `status`', tức chính câu đó khai rằng nó không dùng. R3 thấy chữ, đóng dấu ✅, và số",
|
|
2504
|
+
" lần đọc thật là 0. R3 xác nhận một contract bằng đúng câu văn đang phủ nhận contract.",
|
|
2505
|
+
" 2. chú thích giải thích luật — R9(h): comment viết `scope.kind !== 'all'` trong khi code",
|
|
2506
|
+
" đã thành `false`.",
|
|
2507
|
+
" 3. trích dẫn lịch sử — 'Bản cũ ghi cứng X'. Ca này HỢP LỆ và phải được phép tồn tại:",
|
|
2508
|
+
" framework cố ý giữ luật cũ để người sau biết luật mới chống cái gì.",
|
|
2509
|
+
" 4. substring — `DRIFTED` chứa `DRIFT`. `mentions()` đã chặn được ca này (xem doc-comment",
|
|
2510
|
+
" của nó); ba ca trên thì không.",
|
|
2511
|
+
"",
|
|
2512
|
+
"VÌ SAO KHÔNG SIẾT R3 TOÀN CỤC — hai lý do, cái thứ hai là gốc:",
|
|
2513
|
+
" (a) R3 áp cho 42 tag + 24 cột × 33 lệnh. Siết toàn cục đẻ ra một loạt báo oan, và cái gì",
|
|
2514
|
+
" báo oan thì bị TẮT — rồi mất luôn phần R3 đang bắt thật (G5, G12, G13, G31, G32).",
|
|
2515
|
+
" (b) FILE LỆNH LÀ VĂN XUÔI, VÀ VĂN XUÔI CHÍNH LÀ CHƯƠNG TRÌNH. Với .js thì tách được code",
|
|
2516
|
+
" khỏi comment (`codeOf()`). Với .tmpl thì KHÔNG TỒN TẠI dấu hiệu cú pháp nào tách",
|
|
2517
|
+
" 'câu chỉ dẫn dùng giá trị' khỏi 'câu nói về giá trị' — cả hai đều là câu tiếng Việt.",
|
|
2518
|
+
" Đây là tính chất của thiết kế framework, không sửa được bằng một rule.",
|
|
2519
|
+
"",
|
|
2520
|
+
"NÊN: opt-in, khoanh vùng. Cùng khuôn `positive_assertion_guards` và `checkpoint_levels` —",
|
|
2521
|
+
"khai tường minh từng field nguy hiểm rồi để máy canh, thay vì một cú siết toàn cục.",
|
|
2522
|
+
"",
|
|
2523
|
+
"ANCHOR = DÒNG BẢNG MARKDOWN. Đây không phải heuristic tuỳ ý: framework này viết MỌI luật",
|
|
2524
|
+
"rẽ nhánh bằng bảng — validate-traces Step 3 (`| Rule | Status | Điều kiện |`), gate.md Bước",
|
|
2525
|
+
"3a (`| Mức | Lệnh nào |`), generate-code §Read Trace State (`| Status | Hành động |`),",
|
|
2526
|
+
"dev-run-test §Guard (`| status của row | ghi gì |`). Một field được DÙNG để quyết định thì",
|
|
2527
|
+
"nó xuất hiện trong bảng. Một field chỉ được NHẮC TỚI thì nằm trong câu văn.",
|
|
2528
|
+
"Blockquote (`>`) bị loại: đó là chỗ của giải thích và trích dẫn lịch sử (ca 3 ở trên).",
|
|
2529
|
+
"",
|
|
2530
|
+
"KIỂM CHỨNG ANCHOR trên bản dev-run-test TRƯỚC G55: R3 PASS (lý do G55 sống được),",
|
|
2531
|
+
"R15 FAIL. Và trên bản hiện tại: cả 8 field trong danh sách đều PASS — không báo oan."
|
|
2532
|
+
],
|
|
2533
|
+
"anchor": "markdown_table_row",
|
|
2534
|
+
"$anchor_note": "Dòng có ≥2 ký tự `|` sau khi trim, và KHÔNG bắt đầu bằng `>`. Khớp tên field theo ranh giới token (cùng hàm `mentions()` của R3) — nên `qc_status` KHÔNG thoả cho field `status`.",
|
|
2535
|
+
"fields": [
|
|
2536
|
+
{
|
|
2537
|
+
"field": "status",
|
|
2538
|
+
"actors": [
|
|
2539
|
+
"dev-run-test",
|
|
2540
|
+
"qc-run-test"
|
|
2541
|
+
],
|
|
2542
|
+
"why": "G55 — đây là ca đã xảy ra thật. Không rẽ nhánh theo `status` thì hai lệnh ghi `pass` trên row `DRIFT`, tức dựng lại đúng tín hiệu `/generate-bdd` vừa hạ. Cờ NÓI DỐI, không phải cờ im lặng."
|
|
2543
|
+
},
|
|
2544
|
+
{
|
|
2545
|
+
"field": "spec_ver",
|
|
2546
|
+
"actors": [
|
|
2547
|
+
"generate-code"
|
|
2548
|
+
],
|
|
2549
|
+
"why": "Một nửa của phép so sinh ra DRIFT. Không đọc thì `/generate-code` skip mọi row lỗi thời và không gì báo — spec đổi mà code không bao giờ theo."
|
|
2550
|
+
},
|
|
2551
|
+
{
|
|
2552
|
+
"field": "gen_ver",
|
|
2553
|
+
"actors": [
|
|
2554
|
+
"generate-code"
|
|
2555
|
+
],
|
|
2556
|
+
"why": "Nửa còn lại. Thiếu một nửa thì phép so vô nghĩa, và nó vô nghĩa trong IM LẶNG."
|
|
2557
|
+
},
|
|
2558
|
+
{
|
|
2559
|
+
"field": "implemented_by",
|
|
2560
|
+
"actors": [
|
|
2561
|
+
"generate-code",
|
|
2562
|
+
"generate-bdd"
|
|
2563
|
+
],
|
|
2564
|
+
"why": "Phân biệt UNTRACKED (chưa có code) với ORPHANED (code còn, spec mất). Đọc sai thì `/generate-bdd` xoá row của một scenario ĐÃ có code ⇒ method đó thành vô hình: không cờ nào, không report nào, mà vẫn được caller gọi."
|
|
2565
|
+
},
|
|
2566
|
+
{
|
|
2567
|
+
"field": "test_count",
|
|
2568
|
+
"actors": [
|
|
2569
|
+
"validate-traces"
|
|
2570
|
+
],
|
|
2571
|
+
"why": "Quyết GAP vs OK. Không đọc thì mọi row có code đều thành OK ⇒ coverage báo xanh trên scenario chưa có một test nào."
|
|
2572
|
+
}
|
|
2573
|
+
]
|
|
2574
|
+
},
|
|
2575
|
+
"path_keys": {
|
|
2576
|
+
"$comment": "Key phải có trong templates/project-context.yaml VÀ được dùng bởi ít nhất một actor. Key khai mà không ai dùng = key chết (GAPS.md G17).",
|
|
2577
|
+
"config_file": "templates/project-context.yaml",
|
|
2578
|
+
"ignore_unused": [
|
|
2579
|
+
"specs_dir",
|
|
2580
|
+
"src_dir",
|
|
2581
|
+
"trace_dir",
|
|
2582
|
+
"tech_docs_dir",
|
|
2583
|
+
"lessons_file"
|
|
2584
|
+
]
|
|
2585
|
+
},
|
|
2586
|
+
"forbidden_patterns": [
|
|
2587
|
+
{
|
|
2588
|
+
"pattern": "`integration`",
|
|
2589
|
+
"reason": "Giá trị cột `fe_phase` là `integrated` (CÓ hậu tố -ed). Dạng không -ed chỉ thuộc về CỜ `--phase=integration`. Ghi sai vào sổ thì `--lint-trace` T3 báo lỗi enum, VÀ `fe_integrated` ở /validate-traces Step 7 đếm `integrated` nên counter mãi bằng 0 trong im lặng — đúng hình dạng G1 (cờ im lặng). R6 ĐÃ DỰ ĐOÁN ca này (comment của nó: 'G19 là ca này') và chỉ đúng công cụ là forbidden_patterns — nhưng chưa ai khai. Nó tái diễn thật ở 0.9.0: bốn chỗ trong hai lệnh ghi giá trị cột là dạng không -ed, và CHÍNH validate-traces.tmpl tự mâu thuẫn: một dòng bảo ghi dạng đó, dòng khác đếm `integrated`.",
|
|
2590
|
+
"gap": "G19/G61"
|
|
2591
|
+
},
|
|
2592
|
+
{
|
|
2593
|
+
"pattern": "bdd/{UC-ID}.feature",
|
|
2594
|
+
"reason": "@trace.source thiếu segment {platform}. Layout thật: bdd/{platform}/{UC-ID}-{slug}.feature",
|
|
2595
|
+
"gap": "G8"
|
|
2596
|
+
},
|
|
2597
|
+
{
|
|
2598
|
+
"pattern": "{UC-ID}*-tech-design",
|
|
2599
|
+
"reason": "Glob không bao giờ khớp: tech-doc là doc GỘP cấp PRD, tên mang {TICKET-ID} chứ không mang {UC-ID}",
|
|
2600
|
+
"gap": "G10",
|
|
2601
|
+
"except": {
|
|
2602
|
+
"steps/gate.md": "Trích dẫn pattern trong cảnh báo tại chỗ: \"Đừng glob {UC-ID}*-tech-design*.md — nó nở thành ... và không bao giờ khớp\""
|
|
2603
|
+
}
|
|
2604
|
+
},
|
|
2605
|
+
{
|
|
2606
|
+
"pattern": "{prd-slug}/{UC-ID}.tsv",
|
|
2607
|
+
"reason": "Tên sổ trace thiếu -{platform}. Một sổ cho mỗi UC × platform",
|
|
2608
|
+
"gap": "G18"
|
|
2609
|
+
},
|
|
2610
|
+
{
|
|
2611
|
+
"pattern": "@trace.uc=",
|
|
2612
|
+
"reason": "Từ vựng ĐÃ KHAI TỬ (G11). Số UC đã nằm trong `sc_id` (`{UC-ID}-SC{N}`) nên tag riêng là thừa và gây nhập nhằng với `@trace.ucs` (danh sách UC của tech-doc). Ba file dưới được phép chứa vì chúng đang MAP NGƯỢC nó sang canonical rồi strip — không phải phát ra nó.",
|
|
2613
|
+
"gap": "G11/G30",
|
|
2614
|
+
"except": {
|
|
2615
|
+
"commands/generate-bdd.tmpl": "Đường backward-compat khi nhặt proposal cũ từ feedback/bdd-proposals/",
|
|
2616
|
+
"commands/propose-scenario.tmpl": "Ghi chú cho tester đừng dùng lại format cũ",
|
|
2617
|
+
"commands/review-context.tmpl": "B5 auto-fix: map tag lạc sang canonical rồi strip"
|
|
2618
|
+
}
|
|
2619
|
+
},
|
|
2620
|
+
{
|
|
2621
|
+
"pattern": "@trace.ac=",
|
|
2622
|
+
"reason": "Từ vựng ĐÃ KHAI TỬ (G11) — thay bằng dòng `# Covers: AC{N}`. Xem @trace.uc=.",
|
|
2623
|
+
"gap": "G11/G30",
|
|
2624
|
+
"except": {
|
|
2625
|
+
"commands/generate-bdd.tmpl": "Đường backward-compat cho proposal cũ",
|
|
2626
|
+
"commands/propose-scenario.tmpl": "Ghi chú format cũ",
|
|
2627
|
+
"commands/review-context.tmpl": "B5 auto-fix map sang `# Covers:`"
|
|
2628
|
+
}
|
|
2629
|
+
},
|
|
2630
|
+
{
|
|
2631
|
+
"pattern": "claude-opus-4",
|
|
2632
|
+
"reason": "Hardcode version model — dùng \"model Opus mới nhất\" để không phải sửa framework mỗi lần lên model",
|
|
2633
|
+
"gap": "G21"
|
|
2634
|
+
},
|
|
2635
|
+
{
|
|
2636
|
+
"pattern": "{paths.feature_template}",
|
|
2637
|
+
"reason": "Key chết: template được {{include}} nướng cứng lúc build, lệnh không đọc path template lúc chạy",
|
|
2638
|
+
"gap": "G17"
|
|
2639
|
+
},
|
|
2640
|
+
{
|
|
2641
|
+
"pattern": "{paths.prd_template}",
|
|
2642
|
+
"reason": "Key chết — xem G9/G17",
|
|
2643
|
+
"gap": "G17"
|
|
2644
|
+
},
|
|
2645
|
+
{
|
|
2646
|
+
"pattern": "{paths.trace_report}",
|
|
2647
|
+
"reason": "Key chết và trỏ sai: report thật là {trace_dir}/trace-report.json",
|
|
2648
|
+
"gap": "G17"
|
|
2649
|
+
},
|
|
2650
|
+
{
|
|
2651
|
+
"pattern": "{paths.templates_dir}",
|
|
2652
|
+
"reason": "Key chết — xem G17",
|
|
2653
|
+
"gap": "G17"
|
|
2654
|
+
}
|
|
2655
|
+
]
|
|
2656
|
+
}
|