@torus-engineering/tas-kit 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/tas-adr.md +33 -29
- package/.claude/commands/tas-api-test.md +95 -0
- package/.claude/commands/tas-bug.md +113 -109
- package/.claude/commands/tas-design.md +37 -33
- package/.claude/commands/tas-dev.md +128 -115
- package/.claude/commands/tas-e2e-mobile.md +155 -0
- package/.claude/commands/tas-e2e-web.md +163 -0
- package/.claude/commands/tas-e2e.md +102 -0
- package/.claude/commands/tas-epic.md +35 -31
- package/.claude/commands/tas-feature.md +47 -43
- package/.claude/commands/tas-fix.md +51 -47
- package/.claude/commands/tas-functest-mobile.md +144 -0
- package/.claude/commands/tas-functest-web.md +192 -0
- package/.claude/commands/tas-functest.md +76 -0
- package/.claude/commands/tas-plan.md +200 -184
- package/.claude/commands/tas-prd.md +37 -33
- package/.claude/commands/tas-review.md +111 -104
- package/.claude/commands/tas-sad.md +43 -39
- package/.claude/commands/tas-security.md +81 -80
- package/.claude/commands/tas-story.md +91 -87
- package/.claude/commands/tas-verify.md +51 -41
- package/.claude/rules/common/post-review-agent.md +49 -39
- package/.claude/rules/common/testing.md +24 -0
- package/.claude/rules/common/token-logging.md +27 -0
- package/.claude/rules/csharp/api-testing.md +171 -0
- package/.claude/rules/csharp/patterns.md +10 -0
- package/.claude/rules/python/patterns.md +10 -0
- package/.claude/rules/typescript/patterns.md +10 -0
- package/.claude/rules/web/performance.md +9 -0
- package/.claude/skills/api-design/SKILL.md +3 -1
- package/.claude/skills/{backend-patterns → js-backend-patterns}/SKILL.md +2 -1
- package/.claude/skills/tas-implementation-complete/SKILL.md +99 -97
- package/.claude/skills/tas-tdd/SKILL.md +123 -82
- package/.claude/skills/token-logger/SKILL.md +19 -0
- package/.tas/templates/E2E-Execution-Report.md +198 -0
- package/.tas/templates/E2E-Mobile-Spec.md +130 -0
- package/.tas/templates/E2E-Report.md +174 -0
- package/.tas/templates/E2E-Scenario.md +180 -0
- package/.tas/templates/E2E-Web-Spec.md +164 -0
- package/.tas/templates/Feature.md +55 -55
- package/.tas/templates/Func-Test-Script.md +254 -0
- package/.tas/templates/Func-Test-Spec.md +187 -0
- package/.tas/templates/SAD.md +274 -274
- package/.tas/templates/Story.md +90 -88
- package/bin/cli.js +56 -56
- package/lib/deleted-files.json +33 -0
- package/lib/install.js +213 -176
- package/package.json +34 -34
- package/.claude/agents/README.md +0 -83
- package/.claude/agents/ado-agent.md +0 -39
- package/.claude/agents/code-architect.md +0 -62
- package/.claude/agents/code-simplifier.md +0 -53
- package/.claude/agents/comment-analyzer.md +0 -59
- package/.claude/agents/conversation-analyzer.md +0 -57
- package/.claude/agents/docs-lookup.md +0 -55
- package/.claude/agents/harness-optimizer.md +0 -62
- package/.claude/agents/loop-operator.md +0 -56
- package/.claude/agents/performance-optimizer.md +0 -78
- package/.claude/agents/pr-test-analyzer.md +0 -68
- package/.claude/agents/pytorch-build-resolver.md +0 -76
- package/.claude/agents/refactor-cleaner.md +0 -70
- package/.claude/agents/seo-specialist.md +0 -75
- package/.claude/agents/silent-failure-hunter.md +0 -69
- package/.claude/agents/type-design-analyzer.md +0 -75
- package/.claude/rules/common/agents.md +0 -65
- package/.claude/rules/common/coding-style.md +0 -90
- package/.claude/rules/common/development-workflow.md +0 -44
- package/.claude/rules/common/git-workflow.md +0 -24
- package/.claude/rules/common/performance.md +0 -55
- package/.claude/skills/agent-harness-construction/SKILL.md +0 -77
- package/.claude/skills/agent-introspection-debugging/SKILL.md +0 -157
|
@@ -1,87 +1,91 @@
|
|
|
1
|
-
# /tas-story $ARGUMENTS
|
|
2
|
-
|
|
3
|
-
Vai trò: PE - Product Engineer
|
|
4
|
-
Tạo mới hoặc cập nhật User Story document.
|
|
5
|
-
|
|
6
|
-
**Phạm vi:** Nghiệp vụ, trải nghiệm người dùng, acceptance criteria, test cases.
|
|
7
|
-
**Không thuộc phạm vi:** Kỹ thuật implement, files cần sửa, database schema — đó là việc của `/tas-plan`.
|
|
8
|
-
|
|
9
|
-
## Always / Ask / Never
|
|
10
|
-
|
|
11
|
-
| | Hành động |
|
|
12
|
-
|---|---|
|
|
13
|
-
| **Always** | Viết AC dạng Given/When/Then |
|
|
14
|
-
| **Always** | Set `plan_status: pending` cho Story mới |
|
|
15
|
-
| **Ask** | Khi Story > 8h — gợi ý tách nhỏ |
|
|
16
|
-
| **Never** | Đọc SAD, ADR — kỹ thuật là việc của `/tas-plan` |
|
|
17
|
-
|
|
18
|
-
## Prerequisite
|
|
19
|
-
- Ít nhất một Feature phải tồn tại
|
|
20
|
-
|
|
21
|
-
## Hành động
|
|
22
|
-
|
|
23
|
-
### Chế độ CREATE ($ARGUMENTS là mô tả Story mới, hoặc không có $ARGUMENTS)
|
|
24
|
-
|
|
25
|
-
**Bước 1 — Xác định Feature**
|
|
26
|
-
- Đọc `project.code` từ root/`tas.yaml`
|
|
27
|
-
- Ưu tiên theo thứ tự:
|
|
28
|
-
1. Nếu `$ARGUMENTS` chứa Feature ID → dùng luôn
|
|
29
|
-
2. Nếu context có `parent_id` → dùng luôn
|
|
30
|
-
3. Hỏi user: "Story này thuộc Feature nào?" — không quét thư mục
|
|
31
|
-
|
|
32
|
-
**Bước 2 — Thu thập context nghiệp vụ**
|
|
33
|
-
- Đọc file Feature đã xác định (lấy business context, scope, danh sách Stories hiện có)
|
|
34
|
-
- Đọc PRD (nếu có) — chỉ lấy business requirements, user goals
|
|
35
|
-
|
|
36
|
-
**Bước 3 — Xác định Story ID**
|
|
37
|
-
- Đọc section Stories trong Feature file → xác định index tiếp theo từ danh sách đó
|
|
38
|
-
- KHÔNG quét thư mục
|
|
39
|
-
|
|
40
|
-
**Bước 4 — Soạn Story với user**
|
|
41
|
-
|
|
42
|
-
Thảo luận để điền đầy đủ:
|
|
43
|
-
|
|
44
|
-
a) **User Story**: "As a [role], I want [goal], so that [benefit]"
|
|
45
|
-
|
|
46
|
-
b) **Business Requirements** (nếu có): business rules đặc thù, constraints từ stakeholders
|
|
47
|
-
|
|
48
|
-
c) **Design Notes** (nếu có): UI/UX specs, mockup links, flow diagrams
|
|
49
|
-
|
|
50
|
-
d) **Prerequisites** (nếu có): Stories khác phải done trước
|
|
51
|
-
|
|
52
|
-
e) **Acceptance Criteria**: mỗi AC một kịch bản Given/When/Then rõ ràng
|
|
53
|
-
|
|
54
|
-
**Bước 5 — Test Case Prompting**
|
|
55
|
-
|
|
56
|
-
Sau khi AC được xác nhận, hỏi thêm:
|
|
57
|
-
- "Ngoài happy path, có edge case nào cần test không?" (input rỗng, giá trị biên, concurrent)
|
|
58
|
-
- "Có negative case nào cần cover?" (unauthorized, invalid data, timeout, not found)
|
|
59
|
-
- "Có external dependency nào cần mock khi test?" (API bên ngoài, database state)
|
|
60
|
-
|
|
61
|
-
Ghi tất cả vào section `## Unit Test Cases`.
|
|
62
|
-
|
|
63
|
-
**Bước 6 — Tạo file**
|
|
64
|
-
- Đọc `.tas/templates/Story.md` để lấy format
|
|
65
|
-
- Tạo `docs/epics/{code}-Epic-{NNN}-{slug}/{code}-Feature-{NNN}-{slug}/{code}-Story-{NNN}-{slug}.md`
|
|
66
|
-
- Frontmatter: `plan_status: pending`, `plan_date:` để trống
|
|
67
|
-
|
|
68
|
-
**Bước 7 — Cập nhật project-status.yaml**
|
|
69
|
-
Theo `.claude/rules/common/project-status.md` — thêm entry vào `epics.{EPIC_ID}.features.{FEATURE_ID}.stories`.
|
|
70
|
-
|
|
71
|
-
**Bước 8 — Thông báo next step**
|
|
72
|
-
> "Story đã tạo. Trước khi SE bắt đầu code, cần chạy `/tas-plan {Story-ID}` để lập kế hoạch kỹ thuật."
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
### Chế độ UPDATE ($ARGUMENTS là Story ID, ví dụ: "Story-005")
|
|
77
|
-
|
|
78
|
-
1. Tìm file qua glob `docs/epics/**/{code}-Story-{ID}-*.md`
|
|
79
|
-
2. Đọc file Story hiện tại
|
|
80
|
-
3. Hỏi user cần thay đổi gì (cập nhật AC, đổi status, thêm test cases, sửa business rule...)
|
|
81
|
-
4. Cập nhật file, thêm entry vào Changelog
|
|
82
|
-
5. Cập nhật `project-status.yaml` theo `.claude/rules/common/project-status.md`.
|
|
83
|
-
|
|
84
|
-
## Nguyên tắc
|
|
85
|
-
- Story phải đủ nhỏ để hoàn thành trong **4-8 giờ**; nếu lớn hơn → tách thành nhiều Stories
|
|
86
|
-
- Story file = **product artifact**: mô tả *what* và *why*, không phải *how*
|
|
87
|
-
- Story status: New → Committed → In Progress → Deploy Test → Verify Test → Deploy Stag → Verify Stag → Deploy Prod → Verify Prod → Done
|
|
1
|
+
# /tas-story $ARGUMENTS
|
|
2
|
+
|
|
3
|
+
Vai trò: PE - Product Engineer
|
|
4
|
+
Tạo mới hoặc cập nhật User Story document.
|
|
5
|
+
|
|
6
|
+
**Phạm vi:** Nghiệp vụ, trải nghiệm người dùng, acceptance criteria, test cases.
|
|
7
|
+
**Không thuộc phạm vi:** Kỹ thuật implement, files cần sửa, database schema — đó là việc của `/tas-plan`.
|
|
8
|
+
|
|
9
|
+
## Always / Ask / Never
|
|
10
|
+
|
|
11
|
+
| | Hành động |
|
|
12
|
+
|---|---|
|
|
13
|
+
| **Always** | Viết AC dạng Given/When/Then |
|
|
14
|
+
| **Always** | Set `plan_status: pending` cho Story mới |
|
|
15
|
+
| **Ask** | Khi Story > 8h — gợi ý tách nhỏ |
|
|
16
|
+
| **Never** | Đọc SAD, ADR — kỹ thuật là việc của `/tas-plan` |
|
|
17
|
+
|
|
18
|
+
## Prerequisite
|
|
19
|
+
- Ít nhất một Feature phải tồn tại
|
|
20
|
+
|
|
21
|
+
## Hành động
|
|
22
|
+
|
|
23
|
+
### Chế độ CREATE ($ARGUMENTS là mô tả Story mới, hoặc không có $ARGUMENTS)
|
|
24
|
+
|
|
25
|
+
**Bước 1 — Xác định Feature**
|
|
26
|
+
- Đọc `project.code` từ root/`tas.yaml`
|
|
27
|
+
- Ưu tiên theo thứ tự:
|
|
28
|
+
1. Nếu `$ARGUMENTS` chứa Feature ID → dùng luôn
|
|
29
|
+
2. Nếu context có `parent_id` → dùng luôn
|
|
30
|
+
3. Hỏi user: "Story này thuộc Feature nào?" — không quét thư mục
|
|
31
|
+
|
|
32
|
+
**Bước 2 — Thu thập context nghiệp vụ**
|
|
33
|
+
- Đọc file Feature đã xác định (lấy business context, scope, danh sách Stories hiện có)
|
|
34
|
+
- Đọc PRD (nếu có) — chỉ lấy business requirements, user goals
|
|
35
|
+
|
|
36
|
+
**Bước 3 — Xác định Story ID**
|
|
37
|
+
- Đọc section Stories trong Feature file → xác định index tiếp theo từ danh sách đó
|
|
38
|
+
- KHÔNG quét thư mục
|
|
39
|
+
|
|
40
|
+
**Bước 4 — Soạn Story với user**
|
|
41
|
+
|
|
42
|
+
Thảo luận để điền đầy đủ:
|
|
43
|
+
|
|
44
|
+
a) **User Story**: "As a [role], I want [goal], so that [benefit]"
|
|
45
|
+
|
|
46
|
+
b) **Business Requirements** (nếu có): business rules đặc thù, constraints từ stakeholders
|
|
47
|
+
|
|
48
|
+
c) **Design Notes** (nếu có): UI/UX specs, mockup links, flow diagrams
|
|
49
|
+
|
|
50
|
+
d) **Prerequisites** (nếu có): Stories khác phải done trước
|
|
51
|
+
|
|
52
|
+
e) **Acceptance Criteria**: mỗi AC một kịch bản Given/When/Then rõ ràng
|
|
53
|
+
|
|
54
|
+
**Bước 5 — Test Case Prompting**
|
|
55
|
+
|
|
56
|
+
Sau khi AC được xác nhận, hỏi thêm:
|
|
57
|
+
- "Ngoài happy path, có edge case nào cần test không?" (input rỗng, giá trị biên, concurrent)
|
|
58
|
+
- "Có negative case nào cần cover?" (unauthorized, invalid data, timeout, not found)
|
|
59
|
+
- "Có external dependency nào cần mock khi test?" (API bên ngoài, database state)
|
|
60
|
+
|
|
61
|
+
Ghi tất cả vào section `## Unit Test Cases`.
|
|
62
|
+
|
|
63
|
+
**Bước 6 — Tạo file**
|
|
64
|
+
- Đọc `.tas/templates/Story.md` để lấy format
|
|
65
|
+
- Tạo `docs/epics/{code}-Epic-{NNN}-{slug}/{code}-Feature-{NNN}-{slug}/{code}-Story-{NNN}-{slug}.md`
|
|
66
|
+
- Frontmatter: `plan_status: pending`, `plan_date:` để trống
|
|
67
|
+
|
|
68
|
+
**Bước 7 — Cập nhật project-status.yaml**
|
|
69
|
+
Theo `.claude/rules/common/project-status.md` — thêm entry vào `epics.{EPIC_ID}.features.{FEATURE_ID}.stories`.
|
|
70
|
+
|
|
71
|
+
**Bước 8 — Thông báo next step**
|
|
72
|
+
> "Story đã tạo. Trước khi SE bắt đầu code, cần chạy `/tas-plan {Story-ID}` để lập kế hoạch kỹ thuật."
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Chế độ UPDATE ($ARGUMENTS là Story ID, ví dụ: "Story-005")
|
|
77
|
+
|
|
78
|
+
1. Tìm file qua glob `docs/epics/**/{code}-Story-{ID}-*.md`
|
|
79
|
+
2. Đọc file Story hiện tại
|
|
80
|
+
3. Hỏi user cần thay đổi gì (cập nhật AC, đổi status, thêm test cases, sửa business rule...)
|
|
81
|
+
4. Cập nhật file, thêm entry vào Changelog
|
|
82
|
+
5. Cập nhật `project-status.yaml` theo `.claude/rules/common/project-status.md`.
|
|
83
|
+
|
|
84
|
+
## Nguyên tắc
|
|
85
|
+
- Story phải đủ nhỏ để hoàn thành trong **4-8 giờ**; nếu lớn hơn → tách thành nhiều Stories
|
|
86
|
+
- Story file = **product artifact**: mô tả *what* và *why*, không phải *how*
|
|
87
|
+
- Story status: New → Committed → In Progress → Deploy Test → Verify Test → Deploy Stag → Verify Stag → Deploy Prod → Verify Prod → Done
|
|
88
|
+
|
|
89
|
+
## Bước cuối — Token Log
|
|
90
|
+
|
|
91
|
+
Invoke skill `token-logger`: ghi AI Usage Log vào file Story đang làm việc.
|
|
@@ -1,41 +1,51 @@
|
|
|
1
|
-
# /tas-verify $ARGUMENTS
|
|
2
|
-
|
|
3
|
-
Vai trò: PE - Product Engineer
|
|
4
|
-
Verify Feature trên môi trường Staging (Phase 2).
|
|
5
|
-
|
|
6
|
-
## Prerequisite
|
|
7
|
-
- Feature phải có status "Ready To Verify"
|
|
8
|
-
- Môi trường Staging phải sẵn sàng
|
|
9
|
-
|
|
10
|
-
## Hành động
|
|
11
|
-
1. Cần context từ root/tas.yaml
|
|
12
|
-
2. $ARGUMENTS là Feature ID. Nếu không có, liệt kê features có status "Ready To Verify".
|
|
13
|
-
3. Tìm file Feature trong cây docs/epics/ (dùng glob)
|
|
14
|
-
4. Cần context từ file Feature hiện tại (đặc biệt section Integration Test Cases và E2E Test Cases)
|
|
15
|
-
|
|
16
|
-
### Workflow verify:
|
|
17
|
-
4.5. **
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
1
|
+
# /tas-verify $ARGUMENTS
|
|
2
|
+
|
|
3
|
+
Vai trò: PE - Product Engineer
|
|
4
|
+
Verify Feature trên môi trường Staging (Phase 2).
|
|
5
|
+
|
|
6
|
+
## Prerequisite
|
|
7
|
+
- Feature phải có status "Ready To Verify"
|
|
8
|
+
- Môi trường Staging phải sẵn sàng
|
|
9
|
+
|
|
10
|
+
## Hành động
|
|
11
|
+
1. Cần context từ root/tas.yaml
|
|
12
|
+
2. $ARGUMENTS là Feature ID. Nếu không có, liệt kê features có status "Ready To Verify".
|
|
13
|
+
3. Tìm file Feature trong cây docs/epics/ (dùng glob)
|
|
14
|
+
4. Cần context từ file Feature hiện tại (đặc biệt section Integration Test Cases và E2E Test Cases)
|
|
15
|
+
|
|
16
|
+
### Workflow verify:
|
|
17
|
+
4.5. **Chạy Automated Tests** (nếu có):
|
|
18
|
+
|
|
19
|
+
**Functional Tests** (Layer 2):
|
|
20
|
+
- Kiểm tra `docs/epics/{epic-dir}/{feature-dir}/Func-Test-*.md` đã có chưa
|
|
21
|
+
- Nếu có, hỏi PE: "Chạy functional test suite? Command: `yarn functest:mobile:{feature-slug}` (hoặc `yarn functest:web:{feature-slug}`)"
|
|
22
|
+
- Ghi nhận pass/fail của func suite
|
|
23
|
+
|
|
24
|
+
**E2E Tests** (Layer 3 - nếu Feature có E2E / Acceptance Test Cases):
|
|
25
|
+
> Launch `e2e-runner`: E2E verification cho Feature {ID}.
|
|
26
|
+
> Đọc section `## E2E / Acceptance Test Cases` từ Feature file — list từng test case.
|
|
27
|
+
> Chạy các test cases đó, báo cáo kết quả: Pass/Fail per test case với lý do nếu Fail.
|
|
28
|
+
> Không tự động fix lỗi — chỉ báo cáo kết quả để PE xác nhận.
|
|
29
|
+
|
|
30
|
+
5. **Tổng hợp kết quả và xác nhận với PE**:
|
|
31
|
+
- Hiển thị summary automated test results (Functional + E2E)
|
|
32
|
+
- Hỏi PE: "Automated tests đã pass. Trên Staging thực có vấn đề nào mà automated tests không catch được không? (UX, business logic, edge case thực tế...)"
|
|
33
|
+
|
|
34
|
+
6. Với mỗi issue PE báo cáo hoặc test case FAIL:
|
|
35
|
+
- Hỏi PE mô tả lỗi
|
|
36
|
+
- Tự động tạo Bug trong thư mục Feature đó (dùng logic /tas-bug)
|
|
37
|
+
- Bug có reference đến test case gốc (FT ID hoặc E2E ID), hoặc ghi rõ "phát hiện qua manual verify Staging"
|
|
38
|
+
7. Cập nhật file Feature:
|
|
39
|
+
- Ghi kết quả test (Pass/Fail + ngày) vào từng test case
|
|
40
|
+
- Nếu tất cả Pass: cập nhật Feature status thành "Verified"
|
|
41
|
+
- Nếu có Fail: giữ Feature status "Ready To Verify", liệt kê bugs
|
|
42
|
+
8. Cập nhật root/project-status.yaml
|
|
43
|
+
|
|
44
|
+
## Nguyên tắc
|
|
45
|
+
- KHÔNG skip test case nào, phải verify hết
|
|
46
|
+
- Bug phát hiện ở Phase 2 PHẢI được ghi thành Bug để track
|
|
47
|
+
- Feature chỉ được chuyển sang Phase 3 (Deploy) khi status = "Verified"
|
|
48
|
+
|
|
49
|
+
## Bước cuối — Token Log
|
|
50
|
+
|
|
51
|
+
Invoke skill `token-logger`: ghi AI Usage Log vào file Feature đang verify.
|
|
@@ -1,39 +1,49 @@
|
|
|
1
|
-
# Post-Implementation Review (Isolated Agent)
|
|
2
|
-
|
|
3
|
-
Sau khi implement hoặc fix xong, chạy review qua **Agent độc lập** — không dùng session hiện tại để tránh reviewer bias từ quá trình implement.
|
|
4
|
-
|
|
5
|
-
## Cách dùng
|
|
6
|
-
|
|
7
|
-
Gọi `Agent` tool với prompt sau (thay thế các placeholder `{}`):
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
Bạn là code reviewer. Không có context từ session trước — hãy review hoàn toàn khách quan.
|
|
11
|
-
|
|
12
|
-
Artifact: {path-to-artifact-file}
|
|
13
|
-
Changed files: {danh sách files vừa thay đổi}
|
|
14
|
-
Stack: {stack từ CLAUDE.md}
|
|
15
|
-
|
|
16
|
-
Thực hiện:
|
|
17
|
-
1. Hygiene scan: debug code còn sót (console.log, debugger, print), secrets hardcoded,
|
|
18
|
-
commented-out blocks lớn (>5 dòng).
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
1
|
+
# Post-Implementation Review (Isolated Agent)
|
|
2
|
+
|
|
3
|
+
Sau khi implement hoặc fix xong, chạy review qua **Agent độc lập** — không dùng session hiện tại để tránh reviewer bias từ quá trình implement.
|
|
4
|
+
|
|
5
|
+
## Cách dùng
|
|
6
|
+
|
|
7
|
+
Gọi `Agent` tool với prompt sau (thay thế các placeholder `{}`):
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Bạn là code reviewer. Không có context từ session trước — hãy review hoàn toàn khách quan.
|
|
11
|
+
|
|
12
|
+
Artifact: {path-to-artifact-file}
|
|
13
|
+
Changed files: {danh sách files vừa thay đổi}
|
|
14
|
+
Stack: {stack từ CLAUDE.md}
|
|
15
|
+
|
|
16
|
+
Thực hiện:
|
|
17
|
+
1. Hygiene scan: debug code còn sót (console.log, debugger, print), secrets hardcoded,
|
|
18
|
+
commented-out blocks lớn (>5 dòng).
|
|
19
|
+
1b. Silent failure scan — tìm các pattern sau:
|
|
20
|
+
- Swallowed exceptions: empty catch {}, catch chỉ log nhưng tiếp tục chạy như không có lỗi
|
|
21
|
+
- Silent async failures: fire-and-forget (unawaited task/Promise), async void (.NET),
|
|
22
|
+
.catch(() => {}) không xử lý gì
|
|
23
|
+
- Null blindspots: .FirstOrDefault() dùng trực tiếp không null-check (.NET),
|
|
24
|
+
optional chaining thiếu trên deeply nested object access (TS/JS),
|
|
25
|
+
dict.get() result dùng như non-None (Python)
|
|
26
|
+
- Error propagation sai: HTTP calls không check status trước khi parse,
|
|
27
|
+
hàm return bool/null khi lỗi thay vì throw (caller bỏ qua kết quả)
|
|
28
|
+
- Config reads không check existence
|
|
29
|
+
2. Chạy tests: detect test runner (package.json → npm test / *.csproj → dotnet test /
|
|
30
|
+
pytest.ini → python -m pytest), report kết quả.
|
|
31
|
+
3. Parallel review — launch đồng thời:
|
|
32
|
+
- code-reviewer: đọc .tas/checklists/code-review.md + .claude/rules/common/code-review.md.
|
|
33
|
+
Tập trung: naming, architecture, error handling, DRY, function size, nesting depth.
|
|
34
|
+
- security-reviewer: đọc .claude/rules/common/security.md.
|
|
35
|
+
Tập trung: OWASP Top 10, injection, hardcoded secrets, auth/authz.
|
|
36
|
+
- {lang_agent}: đọc .claude/rules/[stack]/coding-style.md + .claude/rules/[stack]/patterns.md.
|
|
37
|
+
Tập trung: async/await, null handling, type safety, anti-patterns của stack.
|
|
38
|
+
4. Tổng hợp findings: Critical / High / Medium / Low với file:line và fix cụ thể.
|
|
39
|
+
|
|
40
|
+
Trả về Review Summary đầy đủ.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Gate Rule
|
|
44
|
+
|
|
45
|
+
| Kết quả | Hành động |
|
|
46
|
+
|---|---|
|
|
47
|
+
| Có **Critical** hoặc **High** | List findings, **DỪNG**, yêu cầu fix trước khi tiếp tục |
|
|
48
|
+
| Chỉ có **Medium** / **Low** | List gợi ý, hỏi user có muốn fix không, sau đó tiếp tục |
|
|
49
|
+
| Không có findings | Tiếp tục bình thường |
|
|
@@ -28,6 +28,30 @@ MANDATORY workflow:
|
|
|
28
28
|
|
|
29
29
|
- **tdd-guide** - Use PROACTIVELY for new features, enforces write-tests-first
|
|
30
30
|
|
|
31
|
+
## PR Test Gap Analysis
|
|
32
|
+
|
|
33
|
+
Before merging, identify missing tests by categorizing each changed file:
|
|
34
|
+
|
|
35
|
+
| Change type | Tests required |
|
|
36
|
+
|-------------|---------------|
|
|
37
|
+
| New logic added | New unit tests |
|
|
38
|
+
| Logic modified | Updated/new unit tests + regression check |
|
|
39
|
+
| New API endpoint | Integration test (happy path + validation + error) |
|
|
40
|
+
| Bug fix | Regression test that reproduces the bug |
|
|
41
|
+
| Refactor only | Verify existing tests still pass — no new tests needed |
|
|
42
|
+
| Config/infra change | Manual verification step — document it |
|
|
43
|
+
|
|
44
|
+
### How to find gaps
|
|
45
|
+
|
|
46
|
+
1. Run `git diff main...HEAD --name-only` to get changed files
|
|
47
|
+
2. For each changed source file, find its test file (grep for class/function name in test dirs)
|
|
48
|
+
3. Check: happy path covered? edge cases (null, empty, boundary)? failure/error path?
|
|
49
|
+
4. List specific missing test cases with method name and scenario
|
|
50
|
+
|
|
51
|
+
### Regression test rule
|
|
52
|
+
|
|
53
|
+
Every bug fix must include a test that **fails before the fix and passes after**. No exceptions.
|
|
54
|
+
|
|
31
55
|
## Test Structure (AAA Pattern)
|
|
32
56
|
|
|
33
57
|
Prefer Arrange-Act-Assert structure for tests:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Token Usage Logging
|
|
2
|
+
|
|
3
|
+
Ghi `## AI Usage Log` vào cuối artifact file khi TAS command hoàn thành.
|
|
4
|
+
|
|
5
|
+
## Token Estimation
|
|
6
|
+
|
|
7
|
+
Ước tính từ session awareness: số ký tự mỗi file đã `Read` ÷ 4 ≈ tokens (English/code), ÷ 2 (Vietnamese).
|
|
8
|
+
Số ký tự output artifact ÷ 4. Luôn append `(est.)`. User verify bằng `/cost` (CLI) hoặc `/context` (Desktop app).
|
|
9
|
+
|
|
10
|
+
## Format
|
|
11
|
+
|
|
12
|
+
```markdown
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## AI Usage Log
|
|
16
|
+
|
|
17
|
+
| # | Date | Command | Input (est.) | Output (est.) |
|
|
18
|
+
|---|------|---------|-------------|---------------|
|
|
19
|
+
| 1 | YYYY-MM-DD | /tas-{name} | ~{N}k | ~{N}k |
|
|
20
|
+
| 2 | YYYY-MM-DD | /tas-{name} (revision) | ~{N}k | ~{N}k |
|
|
21
|
+
| **Total** | | | **~{N}k** | **~{N}k** |
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Update Rules
|
|
25
|
+
|
|
26
|
+
- **Lần đầu**: section chưa tồn tại → append toàn bộ section với row đầu tiên và row Total
|
|
27
|
+
- **Lần sau**: append row mới trước row Total, cập nhật Total (cộng dồn)
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.cs"
|
|
4
|
+
- "**/ApiTests/**"
|
|
5
|
+
- "**/Api.Tests/**"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# C# API Automation Testing
|
|
9
|
+
|
|
10
|
+
> Dùng bởi `/tas-api-test`. Extends [csharp/testing.md](./testing.md).
|
|
11
|
+
|
|
12
|
+
## Tech Stack
|
|
13
|
+
|
|
14
|
+
| Thành phần | Lựa chọn |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Framework | xUnit (default) — match project nếu đã dùng MSTest/NUnit |
|
|
17
|
+
| Assertions | FluentAssertions |
|
|
18
|
+
| HTTP | System.Net.Http.HttpClient |
|
|
19
|
+
| Config | Microsoft.Extensions.Configuration + JSON/EnvVars |
|
|
20
|
+
|
|
21
|
+
```xml
|
|
22
|
+
<!-- ApiTests.csproj packages -->
|
|
23
|
+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
|
|
24
|
+
<PackageReference Include="xunit" Version="2.*" />
|
|
25
|
+
<PackageReference Include="xunit.runner.visualstudio" Version="2.*" />
|
|
26
|
+
<PackageReference Include="FluentAssertions" Version="6.*" />
|
|
27
|
+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.*" />
|
|
28
|
+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.*" />
|
|
29
|
+
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.*" />
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Project Structure
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
tests/ApiTests/
|
|
36
|
+
appsettings.json # base (không có secrets thật)
|
|
37
|
+
appsettings.Test.json # Test env override
|
|
38
|
+
appsettings.Staging.json # Staging env override
|
|
39
|
+
.gitignore # appsettings.*.local.json
|
|
40
|
+
Shared/
|
|
41
|
+
ApiTestSettings.cs
|
|
42
|
+
TestBase.cs
|
|
43
|
+
v1/
|
|
44
|
+
UsersApiTests.cs
|
|
45
|
+
v2/ # APPEND-ONLY: không sửa v1
|
|
46
|
+
UsersApiTests.cs
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Config
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
// appsettings.json
|
|
53
|
+
{
|
|
54
|
+
"ApiTest": {
|
|
55
|
+
"BaseUrl": "https://localhost:5001",
|
|
56
|
+
"TimeoutSeconds": 30,
|
|
57
|
+
"Auth": { "Type": "Bearer", "TokenEndpoint": "/api/auth/token", "Username": "", "Password": "" }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```csharp
|
|
63
|
+
// ApiTestSettings.cs
|
|
64
|
+
public sealed class ApiTestSettings
|
|
65
|
+
{
|
|
66
|
+
public required string BaseUrl { get; init; }
|
|
67
|
+
public int TimeoutSeconds { get; init; } = 30;
|
|
68
|
+
public required AuthSettings Auth { get; init; }
|
|
69
|
+
}
|
|
70
|
+
public sealed class AuthSettings
|
|
71
|
+
{
|
|
72
|
+
public string Type { get; init; } = "Bearer";
|
|
73
|
+
public string TokenEndpoint { get; init; } = "/api/auth/token";
|
|
74
|
+
public string Username { get; init; } = "";
|
|
75
|
+
public string Password { get; init; } = "";
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```csharp
|
|
80
|
+
// TestBase.cs
|
|
81
|
+
public abstract class TestBase : IAsyncLifetime
|
|
82
|
+
{
|
|
83
|
+
protected HttpClient Client { get; private set; } = null!;
|
|
84
|
+
protected ApiTestSettings Settings { get; private set; } = null!;
|
|
85
|
+
|
|
86
|
+
public async Task InitializeAsync()
|
|
87
|
+
{
|
|
88
|
+
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Test";
|
|
89
|
+
Settings = new ConfigurationBuilder()
|
|
90
|
+
.AddJsonFile("appsettings.json")
|
|
91
|
+
.AddJsonFile($"appsettings.{env}.json", optional: true)
|
|
92
|
+
.AddEnvironmentVariables("APITEST_")
|
|
93
|
+
.Build()
|
|
94
|
+
.GetRequiredSection("ApiTest").Get<ApiTestSettings>()!;
|
|
95
|
+
|
|
96
|
+
Client = new HttpClient { BaseAddress = new Uri(Settings.BaseUrl),
|
|
97
|
+
Timeout = TimeSpan.FromSeconds(Settings.TimeoutSeconds) };
|
|
98
|
+
|
|
99
|
+
if (!string.IsNullOrEmpty(Settings.Auth.Username))
|
|
100
|
+
await AuthenticateAsync();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public Task DisposeAsync() { Client.Dispose(); return Task.CompletedTask; }
|
|
104
|
+
|
|
105
|
+
protected async Task AuthenticateAsync(string? username = null, string? password = null)
|
|
106
|
+
{
|
|
107
|
+
var res = await Client.PostAsJsonAsync(Settings.Auth.TokenEndpoint,
|
|
108
|
+
new { username = username ?? Settings.Auth.Username, password = password ?? Settings.Auth.Password });
|
|
109
|
+
res.EnsureSuccessStatusCode();
|
|
110
|
+
var token = (await res.Content.ReadFromJsonAsync<TokenResponse>())!.AccessToken;
|
|
111
|
+
Client.DefaultRequestHeaders.Authorization =
|
|
112
|
+
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private sealed record TokenResponse(string AccessToken);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Test Class Header (bắt buộc)
|
|
120
|
+
|
|
121
|
+
```csharp
|
|
122
|
+
// ============================================================
|
|
123
|
+
// {Resource} API Tests — v{N}
|
|
124
|
+
// Spec: {spec-file} | Generated: {YYYY-MM-DD} | Story: {ID}
|
|
125
|
+
// APPEND-ONLY: không sửa methods đã tồn tại.
|
|
126
|
+
// ============================================================
|
|
127
|
+
namespace ApiTests.V{N};
|
|
128
|
+
public sealed class {Resource}ApiTests : TestBase
|
|
129
|
+
{
|
|
130
|
+
// Inline DTOs — không import từ production code
|
|
131
|
+
private sealed record {Resource}Dto(Guid Id, string Name);
|
|
132
|
+
private sealed record ListResponse<T>(IReadOnlyList<T> Data, int Total);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Test Naming
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
{HttpMethod}_{Resource}_Returns{Status}_When{Condition}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Ví dụ: `GetById_User_Returns200_WhenExists`, `Create_Order_Returns422_WhenEmailInvalid`
|
|
143
|
+
|
|
144
|
+
AC test: comment `// AC: {text}` ngay dưới XML doc.
|
|
145
|
+
|
|
146
|
+
## XML Doc (bắt buộc trên mỗi test)
|
|
147
|
+
|
|
148
|
+
```csharp
|
|
149
|
+
/// <summary>Verify {METHOD} {path} → {status} khi {condition}. Spec: {ref}</summary>
|
|
150
|
+
[Fact]
|
|
151
|
+
public async Task ...
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Coverage Matrix
|
|
155
|
+
|
|
156
|
+
| Điều kiện | Status | Khi nào |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| Valid, authenticated | 2xx | Luôn |
|
|
159
|
+
| Không có token | 401 | Endpoint yêu cầu auth |
|
|
160
|
+
| Không đủ quyền | 403 | RBAC / ownership |
|
|
161
|
+
| `{id}` không tồn tại | 404 | Có path param |
|
|
162
|
+
| Required field thiếu/sai | 400/422 | Có request body |
|
|
163
|
+
| Business rule (từ AC) | 4xx | Story có AC tương ứng |
|
|
164
|
+
|
|
165
|
+
## CI/CD Env Vars
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
ASPNETCORE_ENVIRONMENT=Test
|
|
169
|
+
APITEST__AUTH__USERNAME=... # double __ cho nested key
|
|
170
|
+
APITEST__AUTH__PASSWORD=...
|
|
171
|
+
```
|
|
@@ -48,3 +48,13 @@ public sealed class PaymentsOptions
|
|
|
48
48
|
- Depend on interfaces at service boundaries
|
|
49
49
|
- Keep constructors focused; if a service needs too many dependencies, split responsibilities
|
|
50
50
|
- Register lifetimes intentionally: singleton for stateless/shared services, scoped for request data, transient for lightweight pure workers
|
|
51
|
+
|
|
52
|
+
## Performance Anti-Patterns
|
|
53
|
+
|
|
54
|
+
Avoid these in hot paths and async contexts:
|
|
55
|
+
|
|
56
|
+
- **Blocking async**: `.Result` or `.Wait()` in async methods — use `await` instead
|
|
57
|
+
- **EF Core N+1**: loading related entities in a loop — use `.Include()` or explicit batch queries
|
|
58
|
+
- **Missing `AsNoTracking()`**: use on read-only queries to reduce EF overhead
|
|
59
|
+
- **Missing `CancellationToken`**: propagate through all public async APIs to enable early exit
|
|
60
|
+
- **Large allocations in hot paths**: prefer `ArrayPool<T>` or `Span<T>` over `new T[]` in frequently called code
|
|
@@ -34,6 +34,16 @@ class CreateUserRequest:
|
|
|
34
34
|
- Use context managers (`with` statement) for resource management
|
|
35
35
|
- Use generators for lazy evaluation and memory-efficient iteration
|
|
36
36
|
|
|
37
|
+
## Performance Anti-Patterns
|
|
38
|
+
|
|
39
|
+
Avoid these in Python services:
|
|
40
|
+
|
|
41
|
+
- **Sync I/O in async handlers**: blocking DB/HTTP calls inside `async def` FastAPI/Django routes — use `await` with async drivers
|
|
42
|
+
- **Missing connection pooling**: configure `pool_size` and `max_overflow` in SQLAlchemy; never create a new engine per request
|
|
43
|
+
- **Heavy computation in request handlers**: offload to Celery background tasks or `asyncio.run_in_executor`
|
|
44
|
+
- **Missing cache on expensive queries**: wrap slow aggregations with Redis (e.g., `aiocache` or `fastapi-cache`)
|
|
45
|
+
- **Loading full querysets when only counts or IDs needed**: use `.values_list()` / `.scalar()` instead of full ORM objects
|
|
46
|
+
|
|
37
47
|
## Reference
|
|
38
48
|
|
|
39
49
|
See skill: `python-patterns` for comprehensive patterns including decorators, concurrency, and package organization.
|
|
@@ -50,3 +50,13 @@ interface Repository<T> {
|
|
|
50
50
|
delete(id: string): Promise<void>
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
|
+
|
|
54
|
+
## Performance Anti-Patterns
|
|
55
|
+
|
|
56
|
+
Avoid these in Node.js backends:
|
|
57
|
+
|
|
58
|
+
- **Sequential awaits that could be parallel**: use `Promise.all()` when calls are independent
|
|
59
|
+
- **CPU-blocking on event loop**: offload heavy computation to worker threads
|
|
60
|
+
- **Missing connection pooling**: never create a new DB connection per request — use pooled clients
|
|
61
|
+
- **ORM N+1**: missing `include`/`select` in Prisma/Sequelize — use eager loading or DataLoader for GraphQL
|
|
62
|
+
- **Large file reads without streaming**: avoid `fs.readFile` on large files — use streams instead
|