mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-01 15:03:57 +08:00
feat(skills): update 12 team skills to v3 design patterns
- Update all 12 team-* SKILL.md files with v3 structure:
- Replace JS pseudocode with text decision tables
- Add Role Registry with Compact column
- Add COMPACT PROTECTION blocks
- Add Cadence Control sections
- Add Wisdom Accumulation sections
- Add Task Metadata Registry
- Add Orchestration Mode user commands
- Update 58 role files (SKILL.md + roles/*):
- Flat-file skills: team-brainstorm, team-issue, team-testing,
team-uidesign, team-planex, team-iterdev
- Folder-based skills: team-review, team-roadmap-dev, team-frontend,
team-quality-assurance, team-tech-debt, team-ultra-analyze
- Preserve special architectures:
- team-planex: 2-member (planner + executor only)
- team-tech-debt: Stop-Wait strategy (run_in_background:false)
- team-iterdev: 7 behavior protocol tables in coordinator
- All 12 teams reviewed for content completeness (PASS)
This commit is contained in:
@@ -6,21 +6,27 @@ allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), Task
|
||||
|
||||
# Team Quality Assurance
|
||||
|
||||
质量保障团队技能。融合"问题发现"和"软件测试"两大能力域,形成"发现→策略→测试→分析"闭环。通过 Scout 多视角扫描、Generator-Executor 循环、共享缺陷模式数据库,实现渐进式质量保障。所有成员通过 `--role=xxx` 路由到角色执行逻辑。
|
||||
Unified team skill: quality assurance combining issue discovery and software testing into a closed loop of scout -> strategy -> generate -> execute -> analyze. Uses multi-perspective scanning, Generator-Executor pipeline, and shared defect pattern database for progressive quality assurance. All team members invoke with `--role=xxx` to route to role-specific execution.
|
||||
|
||||
## Architecture Overview
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ Skill(skill="team-quality-assurance", args="--role=xxx") │
|
||||
└────────────────────────┬─────────────────────────────────┘
|
||||
│ Role Router
|
||||
┌────────┬───────────┼───────────┬──────────┬──────────┐
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
│ Skill(skill="team-quality-assurance") │
|
||||
│ args="<task-description>" or args="--role=xxx" │
|
||||
└────────────────────────────┬─────────────────────────────┘
|
||||
│ Role Router
|
||||
┌──── --role present? ────┐
|
||||
│ NO │ YES
|
||||
↓ ↓
|
||||
Orchestration Mode Role Dispatch
|
||||
(auto -> coordinator) (route to role.md)
|
||||
│
|
||||
┌─────┬──────┴──────┬───────────┬──────────┬──────────┐
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
┌────────┐┌───────┐┌──────────┐┌─────────┐┌────────┐┌────────┐
|
||||
│coordi- ││scout ││strategist││generator││executor││analyst │
|
||||
│nator ││SCOUT-*││QASTRAT-* ││QAGEN-* ││QARUN-* ││QAANA-* │
|
||||
│ roles/ ││ roles/││ roles/ ││ roles/ ││ roles/ ││ roles/ │
|
||||
│ coord ││scout ││strategist││generator││executor││analyst │
|
||||
│ ││SCOUT-*││QASTRAT-* ││QAGEN-* ││QARUN-* ││QAANA-* │
|
||||
└────────┘└───────┘└──────────┘└─────────┘└────────┘└────────┘
|
||||
```
|
||||
|
||||
@@ -29,162 +35,182 @@ allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), Task
|
||||
```
|
||||
roles/
|
||||
├── coordinator/
|
||||
│ ├── role.md # Pipeline 编排(模式选择、任务分发、监控)
|
||||
│ ├── role.md # Pipeline orchestration (mode selection, task dispatch, monitoring)
|
||||
│ └── commands/
|
||||
│ ├── dispatch.md # 任务链创建
|
||||
│ └── monitor.md # 进度监控
|
||||
│ ├── dispatch.md # Task chain creation
|
||||
│ └── monitor.md # Progress monitoring
|
||||
├── scout/
|
||||
│ ├── role.md # 多视角问题扫描
|
||||
│ ├── role.md # Multi-perspective issue scanning
|
||||
│ └── commands/
|
||||
│ └── scan.md # 多视角 CLI Fan-out 扫描
|
||||
│ └── scan.md # Multi-perspective CLI fan-out scanning
|
||||
├── strategist/
|
||||
│ ├── role.md # 测试策略制定
|
||||
│ ├── role.md # Test strategy formulation
|
||||
│ └── commands/
|
||||
│ └── analyze-scope.md # 变更范围分析
|
||||
│ └── analyze-scope.md # Change scope analysis
|
||||
├── generator/
|
||||
│ ├── role.md # 测试用例生成
|
||||
│ ├── role.md # Test case generation
|
||||
│ └── commands/
|
||||
│ └── generate-tests.md # 按层级生成测试代码
|
||||
│ └── generate-tests.md # Layer-based test code generation
|
||||
├── executor/
|
||||
│ ├── role.md # 测试执行与修复
|
||||
│ ├── role.md # Test execution and fix cycles
|
||||
│ └── commands/
|
||||
│ └── run-fix-cycle.md # 迭代测试修复循环
|
||||
│ └── run-fix-cycle.md # Iterative test-fix loop
|
||||
└── analyst/
|
||||
├── role.md # 质量分析报告
|
||||
├── role.md # Quality analysis reporting
|
||||
└── commands/
|
||||
└── quality-report.md # 缺陷模式 + 覆盖率分析
|
||||
└── quality-report.md # Defect pattern + coverage analysis
|
||||
```
|
||||
|
||||
**设计原则**: role.md 保留 Phase 1(Task Discovery)和 Phase 5(Report)内联。Phase 2-4 根据复杂度决定内联或委派到 `commands/*.md`。
|
||||
**Design principle**: role.md retains Phase 1 (Task Discovery) and Phase 5 (Report) inline. Phase 2-4 delegate to `commands/*.md` based on complexity.
|
||||
|
||||
## Role Router
|
||||
|
||||
### Input Parsing
|
||||
|
||||
Parse `$ARGUMENTS` to extract `--role`:
|
||||
Parse `$ARGUMENTS` to extract `--role`. If absent -> Orchestration Mode (auto route to coordinator).
|
||||
|
||||
```javascript
|
||||
const args = "$ARGUMENTS"
|
||||
const roleMatch = args.match(/--role[=\s]+(\w+)/)
|
||||
### Role Registry
|
||||
|
||||
if (!roleMatch) {
|
||||
throw new Error("Missing --role argument. Available roles: coordinator, scout, strategist, generator, executor, analyst")
|
||||
}
|
||||
| Role | File | Task Prefix | Type | Compact |
|
||||
|------|------|-------------|------|---------|
|
||||
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | (none) | orchestrator | **compressed -> must re-read** |
|
||||
| scout | [roles/scout/role.md](roles/scout/role.md) | SCOUT-* | pipeline | compressed -> must re-read |
|
||||
| strategist | [roles/strategist/role.md](roles/strategist/role.md) | QASTRAT-* | pipeline | compressed -> must re-read |
|
||||
| generator | [roles/generator/role.md](roles/generator/role.md) | QAGEN-* | pipeline | compressed -> must re-read |
|
||||
| executor | [roles/executor/role.md](roles/executor/role.md) | QARUN-* | pipeline | compressed -> must re-read |
|
||||
| analyst | [roles/analyst/role.md](roles/analyst/role.md) | QAANA-* | pipeline | compressed -> must re-read |
|
||||
|
||||
const role = roleMatch[1]
|
||||
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "quality-assurance"
|
||||
> **COMPACT PROTECTION**: Role files are execution documents, not reference material. When context compression occurs and role instructions are reduced to summaries, **you MUST immediately `Read` the corresponding role.md to reload before continuing execution**. Do not execute any Phase based on summaries.
|
||||
|
||||
### Dispatch
|
||||
|
||||
1. Extract `--role` from arguments
|
||||
2. If no `--role` -> route to coordinator (Orchestration Mode)
|
||||
3. Look up role in registry -> Read the role file -> Execute its phases
|
||||
|
||||
### Orchestration Mode
|
||||
|
||||
When invoked without `--role`, coordinator auto-starts. User just provides task description.
|
||||
|
||||
**Invocation**: `Skill(skill="team-quality-assurance", args="<task-description>")`
|
||||
|
||||
**Lifecycle**:
|
||||
```
|
||||
User provides task description
|
||||
-> coordinator Phase 1-3: Mode detection + requirement clarification -> TeamCreate -> Create task chain
|
||||
-> coordinator Phase 4: spawn first batch workers (background) -> STOP
|
||||
-> Worker executes -> SendMessage callback -> coordinator advances next step
|
||||
-> Loop until pipeline complete -> Phase 5 report
|
||||
```
|
||||
|
||||
### Role Dispatch
|
||||
**User Commands** (wake paused coordinator):
|
||||
|
||||
```javascript
|
||||
const VALID_ROLES = {
|
||||
"coordinator": { file: "roles/coordinator/role.md", prefix: null },
|
||||
"scout": { file: "roles/scout/role.md", prefix: "SCOUT" },
|
||||
"strategist": { file: "roles/strategist/role.md", prefix: "QASTRAT" },
|
||||
"generator": { file: "roles/generator/role.md", prefix: "QAGEN" },
|
||||
"executor": { file: "roles/executor/role.md", prefix: "QARUN" },
|
||||
"analyst": { file: "roles/analyst/role.md", prefix: "QAANA" }
|
||||
}
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| `check` / `status` | Output execution status graph, no advancement |
|
||||
| `resume` / `continue` | Check worker states, advance next step |
|
||||
|
||||
if (!VALID_ROLES[role]) {
|
||||
throw new Error(`Unknown role: ${role}. Available: ${Object.keys(VALID_ROLES).join(', ')}`)
|
||||
}
|
||||
|
||||
// Read and execute role-specific logic
|
||||
Read(VALID_ROLES[role].file)
|
||||
// → Execute the 5-phase process defined in that file
|
||||
```
|
||||
|
||||
### Available Roles
|
||||
|
||||
| Role | Task Prefix | Responsibility | Role File |
|
||||
|------|-------------|----------------|-----------|
|
||||
| `coordinator` | N/A | QA pipeline 编排、模式选择、质量门控 | [roles/coordinator/role.md](roles/coordinator/role.md) |
|
||||
| `scout` | SCOUT-* | 多视角问题扫描、主动发现潜在缺陷 | [roles/scout/role.md](roles/scout/role.md) |
|
||||
| `strategist` | QASTRAT-* | 变更范围分析、测试层级选择、覆盖率目标 | [roles/strategist/role.md](roles/strategist/role.md) |
|
||||
| `generator` | QAGEN-* | 按层级生成测试用例(unit/integration/E2E) | [roles/generator/role.md](roles/generator/role.md) |
|
||||
| `executor` | QARUN-* | 执行测试、收集覆盖率、自动修复循环 | [roles/executor/role.md](roles/executor/role.md) |
|
||||
| `analyst` | QAANA-* | 缺陷模式分析、覆盖率差距、质量报告 | [roles/analyst/role.md](roles/analyst/role.md) |
|
||||
---
|
||||
|
||||
## Shared Infrastructure
|
||||
|
||||
### Role Isolation Rules
|
||||
The following templates apply to all worker roles. Each role.md only needs to write **Phase 2-4** role-specific logic.
|
||||
|
||||
**核心原则**: 每个角色仅能执行自己职责范围内的工作。
|
||||
### Worker Phase 1: Task Discovery (shared by all workers)
|
||||
|
||||
#### Output Tagging(强制)
|
||||
Every worker executes the same task discovery flow on startup:
|
||||
|
||||
所有角色的输出必须带 `[role_name]` 标识前缀:
|
||||
1. Call `TaskList()` to get all tasks
|
||||
2. Filter: subject matches this role's prefix + owner is this role + status is pending + blockedBy is empty
|
||||
3. No tasks -> idle wait
|
||||
4. Has tasks -> `TaskGet` for details -> `TaskUpdate` mark in_progress
|
||||
|
||||
```javascript
|
||||
SendMessage({ content: `## [${role}] ...`, summary: `[${role}] ...` })
|
||||
mcp__ccw-tools__team_msg({ summary: `[${role}] ...` })
|
||||
**Resume Artifact Check** (prevent duplicate output after resume):
|
||||
- Check whether this task's output artifact already exists
|
||||
- Artifact complete -> skip to Phase 5 report completion
|
||||
- Artifact incomplete or missing -> normal Phase 2-4 execution
|
||||
|
||||
### Worker Phase 5: Report (shared by all workers)
|
||||
|
||||
Standard reporting flow after task completion:
|
||||
|
||||
1. **Message Bus**: Call `mcp__ccw-tools__team_msg` to log message
|
||||
- Parameters: operation="log", team="quality-assurance", from=<role>, to="coordinator", type=<message-type>, summary="[<role>] <summary>", ref=<artifact-path>
|
||||
- **CLI fallback**: When MCP unavailable -> `ccw team log --team quality-assurance --from <role> --to coordinator --type <type> --summary "[<role>] ..." --json`
|
||||
2. **SendMessage**: Send result to coordinator (content and summary both prefixed with `[<role>]`)
|
||||
3. **TaskUpdate**: Mark task completed
|
||||
4. **Loop**: Return to Phase 1 to check next task
|
||||
|
||||
### Wisdom Accumulation (all roles)
|
||||
|
||||
Cross-task knowledge accumulation. Coordinator creates `wisdom/` directory at session initialization.
|
||||
|
||||
**Directory**:
|
||||
```
|
||||
<session-folder>/wisdom/
|
||||
├── learnings.md # Patterns and insights
|
||||
├── decisions.md # Architecture and design decisions
|
||||
├── conventions.md # Codebase conventions
|
||||
└── issues.md # Known risks and issues
|
||||
```
|
||||
|
||||
#### Coordinator 隔离
|
||||
**Worker Load** (Phase 2): Extract `Session: <path>` from task description, read wisdom directory files.
|
||||
**Worker Contribute** (Phase 4/5): Write this task's discoveries to corresponding wisdom files.
|
||||
|
||||
| 允许 | 禁止 |
|
||||
|------|------|
|
||||
| 需求澄清 (AskUserQuestion) | ❌ 直接编写测试 |
|
||||
| 创建任务链 (TaskCreate) | ❌ 直接执行测试或扫描 |
|
||||
| 模式选择 + 质量门控 | ❌ 直接分析覆盖率 |
|
||||
| 监控进度 (消息总线) | ❌ 绕过 worker 自行完成 |
|
||||
### Role Isolation Rules
|
||||
|
||||
#### Worker 隔离
|
||||
#### Output Tagging
|
||||
|
||||
| 允许 | 禁止 |
|
||||
|------|------|
|
||||
| 处理自己前缀的任务 | ❌ 处理其他角色前缀的任务 |
|
||||
| 读写 shared-memory.json (自己的字段) | ❌ 为其他角色创建任务 |
|
||||
| SendMessage 给 coordinator | ❌ 直接与其他 worker 通信 |
|
||||
All outputs must carry `[role_name]` prefix.
|
||||
|
||||
#### Coordinator Isolation
|
||||
|
||||
| Allowed | Forbidden |
|
||||
|---------|-----------|
|
||||
| Requirement clarification (AskUserQuestion) | Direct test writing |
|
||||
| Create task chain (TaskCreate) | Direct test execution or scanning |
|
||||
| Mode selection + quality gating | Direct coverage analysis |
|
||||
| Monitor progress (message bus) | Bypassing workers |
|
||||
|
||||
#### Worker Isolation
|
||||
|
||||
| Allowed | Forbidden |
|
||||
|---------|-----------|
|
||||
| Process tasks with own prefix | Process tasks with other role prefixes |
|
||||
| Read/write shared-memory.json (own fields) | Create tasks for other roles |
|
||||
| SendMessage to coordinator | Communicate directly with other workers |
|
||||
| Delegate to commands/ files | Modify resources outside own responsibility |
|
||||
|
||||
### Team Configuration
|
||||
|
||||
```javascript
|
||||
const TEAM_CONFIG = {
|
||||
name: "quality-assurance",
|
||||
sessionDir: ".workflow/.team/QA-{slug}-{date}/",
|
||||
sharedMemory: "shared-memory.json",
|
||||
testLayers: {
|
||||
L1: { name: "Unit Tests", coverage_target: 80 },
|
||||
L2: { name: "Integration Tests", coverage_target: 60 },
|
||||
L3: { name: "E2E Tests", coverage_target: 40 }
|
||||
},
|
||||
scanPerspectives: ["bug", "security", "ux", "test-coverage", "code-quality"]
|
||||
}
|
||||
```
|
||||
| Setting | Value |
|
||||
|---------|-------|
|
||||
| Team name | quality-assurance |
|
||||
| Session directory | `.workflow/.team/QA-<slug>-<date>/` |
|
||||
| Test layers | L1: Unit (80%), L2: Integration (60%), L3: E2E (40%) |
|
||||
| Scan perspectives | bug, security, ux, test-coverage, code-quality |
|
||||
|
||||
### Shared Memory(核心创新)
|
||||
### Shared Memory
|
||||
|
||||
```javascript
|
||||
// 各角色读取共享记忆
|
||||
const memoryPath = `${sessionFolder}/shared-memory.json`
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
|
||||
Cross-role accumulated knowledge stored in `shared-memory.json`:
|
||||
|
||||
// 各角色写入自己负责的字段:
|
||||
// scout → sharedMemory.discovered_issues
|
||||
// strategist → sharedMemory.test_strategy
|
||||
// generator → sharedMemory.generated_tests
|
||||
// executor → sharedMemory.execution_results
|
||||
// analyst → sharedMemory.defect_patterns + quality_score + coverage_history
|
||||
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
|
||||
```
|
||||
| Field | Owner | Content |
|
||||
|-------|-------|---------|
|
||||
| `discovered_issues` | scout | Multi-perspective scan findings |
|
||||
| `test_strategy` | strategist | Layer selection, coverage targets, scope |
|
||||
| `generated_tests` | generator | Test file paths and metadata |
|
||||
| `execution_results` | executor | Test run results and coverage data |
|
||||
| `defect_patterns` | analyst | Recurring defect pattern database |
|
||||
| `quality_score` | analyst | Overall quality assessment |
|
||||
| `coverage_history` | analyst | Coverage trend over time |
|
||||
|
||||
Each role reads in Phase 2, writes own fields in Phase 5.
|
||||
|
||||
### Message Bus (All Roles)
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: role,
|
||||
to: "coordinator",
|
||||
type: "<type>",
|
||||
summary: `[${role}] <summary>`,
|
||||
ref: "<file_path>"
|
||||
})
|
||||
```
|
||||
Every SendMessage **before**, must call `mcp__ccw-tools__team_msg` to log.
|
||||
|
||||
**Message types by role**:
|
||||
|
||||
| Role | Types |
|
||||
|------|-------|
|
||||
@@ -195,73 +221,222 @@ mcp__ccw-tools__team_msg({
|
||||
| executor | `tests_passed`, `tests_failed`, `coverage_report`, `error` |
|
||||
| analyst | `analysis_ready`, `quality_report`, `error` |
|
||||
|
||||
### CLI 回退
|
||||
|
||||
```javascript
|
||||
Bash(`ccw team log --team "${teamName}" --from "${role}" --to "coordinator" --type "<type>" --summary "<摘要>" --json`)
|
||||
```
|
||||
|
||||
### Task Lifecycle (All Worker Roles)
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith(`${VALID_ROLES[role].prefix}-`) &&
|
||||
t.owner === role &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
if (myTasks.length === 0) return
|
||||
const task = TaskGet({ taskId: myTasks[0].id })
|
||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||
|
||||
// Phase 2-4: Role-specific
|
||||
// Phase 5: Report + Loop
|
||||
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: role, to: "coordinator", type: "...", summary: `[${role}] ...` })
|
||||
SendMessage({ type: "message", recipient: "coordinator", content: `## [${role}] ...`, summary: `[${role}] ...` })
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
```
|
||||
---
|
||||
|
||||
## Three-Mode Pipeline Architecture
|
||||
|
||||
```
|
||||
Discovery Mode (问题发现优先):
|
||||
SCOUT-001(多视角扫描) → QASTRAT-001 → QAGEN-001 → QARUN-001 → QAANA-001
|
||||
|
||||
Testing Mode (测试优先,跳过 scout):
|
||||
QASTRAT-001(变更分析) → QAGEN-001(L1) → QARUN-001(L1) → QAGEN-002(L2) → QARUN-002(L2) → QAANA-001
|
||||
|
||||
Full QA Mode (完整闭环):
|
||||
SCOUT-001(扫描) → QASTRAT-001(策略) → [QAGEN-001(L1) + QAGEN-002(L2)](parallel) → [QARUN-001 + QARUN-002](parallel) → QAANA-001(分析) → SCOUT-002(回归扫描)
|
||||
```
|
||||
|
||||
### Mode Auto-Detection
|
||||
|
||||
```javascript
|
||||
function detectQAMode(args, taskDescription) {
|
||||
if (/--mode[=\s]+(discovery|testing|full)/.test(args)) {
|
||||
return args.match(/--mode[=\s]+(\w+)/)[1]
|
||||
}
|
||||
// 自动检测
|
||||
if (/发现|扫描|scan|discover|issue|问题/.test(taskDescription)) return 'discovery'
|
||||
if (/测试|test|覆盖|coverage|TDD/.test(taskDescription)) return 'testing'
|
||||
return 'full'
|
||||
}
|
||||
```
|
||||
| Condition | Mode |
|
||||
|-----------|------|
|
||||
| Explicit `--mode=discovery` flag | discovery |
|
||||
| Explicit `--mode=testing` flag | testing |
|
||||
| Explicit `--mode=full` flag | full |
|
||||
| Task description contains: discovery/scan/issue keywords | discovery |
|
||||
| Task description contains: test/coverage/TDD keywords | testing |
|
||||
| No explicit flag and no keyword match | full (default) |
|
||||
|
||||
### Generator-Executor Loop (GC 循环)
|
||||
### Pipeline Diagrams
|
||||
|
||||
```
|
||||
QAGEN → QARUN → (if coverage < target) → QAGEN-fix → QARUN-2
|
||||
(if coverage >= target) → next layer or QAANA
|
||||
Discovery Mode (issue discovery first):
|
||||
SCOUT-001(multi-perspective scan) -> QASTRAT-001 -> QAGEN-001 -> QARUN-001 -> QAANA-001
|
||||
|
||||
Testing Mode (skip scout, test first):
|
||||
QASTRAT-001(change analysis) -> QAGEN-001(L1) -> QARUN-001(L1) -> QAGEN-002(L2) -> QARUN-002(L2) -> QAANA-001
|
||||
|
||||
Full QA Mode (complete closed loop):
|
||||
SCOUT-001(scan) -> QASTRAT-001(strategy)
|
||||
-> [QAGEN-001(L1) || QAGEN-002(L2)](parallel) -> [QARUN-001 || QARUN-002](parallel)
|
||||
-> QAANA-001(analysis) -> SCOUT-002(regression scan)
|
||||
```
|
||||
|
||||
### Generator-Executor Pipeline (GC Loop)
|
||||
|
||||
Generator and executor iterate per test layer until coverage targets are met:
|
||||
|
||||
```
|
||||
QAGEN -> QARUN -> (if coverage < target) -> QAGEN-fix -> QARUN-2
|
||||
(if coverage >= target) -> next layer or QAANA
|
||||
```
|
||||
|
||||
Coordinator monitors GC loop progress. After 3 GC iterations without convergence, accept current coverage with warning.
|
||||
|
||||
In Full QA mode, spawn N generator agents in parallel (one per test layer). Each receives a QAGEN-N task with layer assignment. Use `run_in_background: true` for all spawns, then coordinator stops and waits for callbacks. Similarly spawn N executor agents in parallel for QARUN-N tasks.
|
||||
|
||||
### Cadence Control
|
||||
|
||||
**Beat model**: Event-driven, each beat = coordinator wake -> process -> spawn -> STOP.
|
||||
|
||||
```
|
||||
Beat Cycle (single beat)
|
||||
═══════════════════════════════════════════════════════════
|
||||
Event Coordinator Workers
|
||||
───────────────────────────────────────────────────────────
|
||||
callback/resume ──> ┌─ handleCallback ─┐
|
||||
│ mark completed │
|
||||
│ check pipeline │
|
||||
├─ handleSpawnNext ─┤
|
||||
│ find ready tasks │
|
||||
│ spawn workers ───┼──> [Worker A] Phase 1-5
|
||||
│ (parallel OK) ──┼──> [Worker B] Phase 1-5
|
||||
└─ STOP (idle) ─────┘ │
|
||||
│
|
||||
callback <─────────────────────────────────────────┘
|
||||
(next beat) SendMessage + TaskUpdate(completed)
|
||||
═══════════════════════════════════════════════════════════
|
||||
```
|
||||
|
||||
**Pipeline beat view**:
|
||||
|
||||
```
|
||||
Discovery mode (5 beats, strictly serial)
|
||||
──────────────────────────────────────────────────────────
|
||||
Beat 1 2 3 4 5
|
||||
│ │ │ │ │
|
||||
SCOUT -> STRAT -> GEN -> RUN -> ANA
|
||||
▲ ▲
|
||||
pipeline pipeline
|
||||
start done
|
||||
|
||||
S=SCOUT STRAT=QASTRAT GEN=QAGEN RUN=QARUN ANA=QAANA
|
||||
|
||||
Testing mode (6 beats, layer progression)
|
||||
──────────────────────────────────────────────────────────
|
||||
Beat 1 2 3 4 5 6
|
||||
│ │ │ │ │ │
|
||||
STRAT -> GEN-L1 -> RUN-L1 -> GEN-L2 -> RUN-L2 -> ANA
|
||||
▲ ▲
|
||||
no scout analysis
|
||||
(test only)
|
||||
|
||||
Full QA mode (6 beats, with parallel windows + regression)
|
||||
──────────────────────────────────────────────────────────
|
||||
Beat 1 2 3 4 5 6
|
||||
│ │ ┌────┴────┐ ┌────┴────┐ │ │
|
||||
SCOUT -> STRAT -> GEN-L1||GEN-L2 -> RUN-1||RUN-2 -> ANA -> SCOUT-2
|
||||
▲ ▲
|
||||
parallel gen regression
|
||||
scan
|
||||
```
|
||||
|
||||
**Checkpoints**:
|
||||
|
||||
| Trigger | Location | Behavior |
|
||||
|---------|----------|----------|
|
||||
| GC loop limit | QARUN coverage < target | After 3 iterations, accept current coverage with warning |
|
||||
| Pipeline stall | No ready + no running | Check missing tasks, report to user |
|
||||
| Regression scan (full mode) | QAANA-001 complete | Trigger SCOUT-002 for regression verification |
|
||||
|
||||
**Stall Detection** (coordinator `handleCheck` executes):
|
||||
|
||||
| Check | Condition | Resolution |
|
||||
|-------|-----------|------------|
|
||||
| Worker no response | in_progress task no callback | Report waiting task list, suggest user `resume` |
|
||||
| Pipeline deadlock | no ready + no running + has pending | Check blockedBy dependency chain, report blocking point |
|
||||
| GC loop exceeded | generator/executor iteration > 3 | Terminate loop, output latest coverage report |
|
||||
|
||||
### Task Metadata Registry
|
||||
|
||||
| Task ID | Role | Phase | Dependencies | Description |
|
||||
|---------|------|-------|-------------|-------------|
|
||||
| SCOUT-001 | scout | discovery | (none) | Multi-perspective issue scanning |
|
||||
| QASTRAT-001 | strategist | strategy | SCOUT-001 or (none) | Change scope analysis + test strategy |
|
||||
| QAGEN-001 | generator | generation | QASTRAT-001 | L1 unit test generation |
|
||||
| QAGEN-002 | generator | generation | QASTRAT-001 (full mode) | L2 integration test generation |
|
||||
| QARUN-001 | executor | execution | QAGEN-001 | L1 test execution + fix cycles |
|
||||
| QARUN-002 | executor | execution | QAGEN-002 (full mode) | L2 test execution + fix cycles |
|
||||
| QAANA-001 | analyst | analysis | QARUN-001 (+ QARUN-002) | Defect pattern analysis + quality report |
|
||||
| SCOUT-002 | scout | regression | QAANA-001 (full mode) | Regression scan after fixes |
|
||||
|
||||
---
|
||||
|
||||
## Coordinator Spawn Template
|
||||
|
||||
When coordinator spawns workers, use background mode (Spawn-and-Stop):
|
||||
|
||||
```
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
description: "Spawn <role> worker",
|
||||
team_name: <team-name>,
|
||||
name: "<role>",
|
||||
run_in_background: true,
|
||||
prompt: `You are team "<team-name>" <ROLE>.
|
||||
|
||||
## Primary Directive
|
||||
All your work must be executed through Skill to load role definition:
|
||||
Skill(skill="team-quality-assurance", args="--role=<role>")
|
||||
|
||||
Current requirement: <task-description>
|
||||
Session: <session-folder>
|
||||
|
||||
## Role Guidelines
|
||||
- Only process <PREFIX>-* tasks, do not execute other role work
|
||||
- All output prefixed with [<role>] identifier
|
||||
- Only communicate with coordinator
|
||||
- Do not use TaskCreate for other roles
|
||||
- Call mcp__ccw-tools__team_msg before every SendMessage
|
||||
|
||||
## Workflow
|
||||
1. Call Skill -> load role definition and execution logic
|
||||
2. Follow role.md 5-Phase flow
|
||||
3. team_msg + SendMessage results to coordinator
|
||||
4. TaskUpdate completed -> check next task`
|
||||
})
|
||||
```
|
||||
|
||||
### Parallel Spawn (N agents for same role)
|
||||
|
||||
> When pipeline has parallel tasks assigned to the same role, spawn N distinct agents with unique names. A single agent can only process tasks serially.
|
||||
|
||||
**Parallel detection**:
|
||||
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| N parallel tasks for same role prefix | Spawn N agents named `<role>-1`, `<role>-2` ... |
|
||||
| Single task for role | Standard spawn (single agent) |
|
||||
|
||||
**Parallel spawn template**:
|
||||
|
||||
```
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
description: "Spawn <role>-<N> worker",
|
||||
team_name: <team-name>,
|
||||
name: "<role>-<N>",
|
||||
run_in_background: true,
|
||||
prompt: `You are team "<team-name>" <ROLE> (<role>-<N>).
|
||||
Your agent name is "<role>-<N>", use this name for task discovery owner matching.
|
||||
|
||||
## Primary Directive
|
||||
Skill(skill="team-quality-assurance", args="--role=<role> --agent-name=<role>-<N>")
|
||||
|
||||
## Role Guidelines
|
||||
- Only process tasks where owner === "<role>-<N>" with <PREFIX>-* prefix
|
||||
- All output prefixed with [<role>] identifier
|
||||
|
||||
## Workflow
|
||||
1. TaskList -> find tasks where owner === "<role>-<N>" with <PREFIX>-* prefix
|
||||
2. Skill -> execute role definition
|
||||
3. team_msg + SendMessage results to coordinator
|
||||
4. TaskUpdate completed -> check next task`
|
||||
})
|
||||
```
|
||||
|
||||
**Dispatch must match agent names**: In dispatch, parallel tasks use instance-specific owner: `<role>-<N>`. In role.md, task discovery uses --agent-name for owner matching.
|
||||
|
||||
## Unified Session Directory
|
||||
|
||||
```
|
||||
.workflow/.team/QA-{slug}-{YYYY-MM-DD}/
|
||||
├── team-session.json
|
||||
├── shared-memory.json # 发现的问题 / 测试策略 / 缺陷模式 / 覆盖率历史
|
||||
.workflow/.team/QA-<slug>-<YYYY-MM-DD>/
|
||||
├── team-session.json # Session state
|
||||
├── shared-memory.json # Discovered issues / test strategy / defect patterns / coverage history
|
||||
├── wisdom/ # Cross-task knowledge
|
||||
│ ├── learnings.md
|
||||
│ ├── decisions.md
|
||||
│ ├── conventions.md
|
||||
│ └── issues.md
|
||||
├── scan/ # Scout output
|
||||
│ └── scan-results.json
|
||||
├── strategy/ # Strategist output
|
||||
@@ -277,218 +452,13 @@ QAGEN → QARUN → (if coverage < target) → QAGEN-fix → QARUN-2
|
||||
└── quality-report.md
|
||||
```
|
||||
|
||||
## Coordinator Spawn Template
|
||||
|
||||
```javascript
|
||||
TeamCreate({ team_name: teamName })
|
||||
|
||||
// Scout
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
description: `Spawn scout worker`,
|
||||
team_name: teamName,
|
||||
name: "scout",
|
||||
prompt: `你是 team "${teamName}" 的 SCOUT。
|
||||
|
||||
当你收到 SCOUT-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=scout") 执行。
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
约束: ${constraints}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 SCOUT-* 前缀的任务,不得执行其他角色的工作
|
||||
- 所有输出(SendMessage、team_msg)必须带 [scout] 标识前缀
|
||||
- 仅与 coordinator 通信,不得直接联系其他 worker
|
||||
- 不得使用 TaskCreate 为其他角色创建任务
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
工作流程:
|
||||
1. TaskList → 找到 SCOUT-* 任务
|
||||
2. Skill(skill="team-quality-assurance", args="--role=scout") 执行
|
||||
3. team_msg log + SendMessage 结果给 coordinator(带 [scout] 标识)
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
|
||||
// Strategist
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
description: `Spawn strategist worker`,
|
||||
team_name: teamName,
|
||||
name: "strategist",
|
||||
prompt: `你是 team "${teamName}" 的 STRATEGIST。
|
||||
|
||||
当你收到 QASTRAT-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=strategist") 执行。
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
约束: ${constraints}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 QASTRAT-* 前缀的任务
|
||||
- 所有输出必须带 [strategist] 标识前缀
|
||||
- 仅与 coordinator 通信
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
工作流程:
|
||||
1. TaskList → 找到 QASTRAT-* 任务
|
||||
2. Skill(skill="team-quality-assurance", args="--role=strategist") 执行
|
||||
3. team_msg log + SendMessage 结果给 coordinator
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
|
||||
// Generator — parallel instances for full mode (generator-1, generator-2)
|
||||
const isFullMode = qaMode === 'full'
|
||||
|
||||
if (isFullMode) {
|
||||
for (let i = 1; i <= 2; i++) {
|
||||
const agentName = `generator-${i}`
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
description: `Spawn ${agentName} worker`,
|
||||
team_name: teamName,
|
||||
name: agentName,
|
||||
prompt: `你是 team "${teamName}" 的 GENERATOR (${agentName})。
|
||||
你的 agent 名称是 "${agentName}",任务发现时用此名称匹配 owner。
|
||||
|
||||
当你收到 QAGEN-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=generator --agent-name=${agentName}") 执行。
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 owner 为 "${agentName}" 的 QAGEN-* 前缀任务
|
||||
- 所有输出必须带 [generator] 标识前缀
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
工作流程:
|
||||
1. TaskList → 找到 owner === "${agentName}" 的 QAGEN-* 任务
|
||||
2. Skill(skill="team-quality-assurance", args="--role=generator --agent-name=${agentName}") 执行
|
||||
3. team_msg log + SendMessage
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
description: `Spawn generator worker`,
|
||||
team_name: teamName,
|
||||
name: "generator",
|
||||
prompt: `你是 team "${teamName}" 的 GENERATOR。
|
||||
|
||||
当你收到 QAGEN-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=generator") 执行。
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 QAGEN-* 前缀的任务
|
||||
- 所有输出必须带 [generator] 标识前缀
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
工作流程:
|
||||
1. TaskList → 找到 QAGEN-* 任务
|
||||
2. Skill(skill="team-quality-assurance", args="--role=generator") 执行
|
||||
3. team_msg log + SendMessage
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
}
|
||||
|
||||
// Executor — parallel instances for full mode (executor-1, executor-2)
|
||||
if (isFullMode) {
|
||||
for (let i = 1; i <= 2; i++) {
|
||||
const agentName = `executor-${i}`
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
description: `Spawn ${agentName} worker`,
|
||||
team_name: teamName,
|
||||
name: agentName,
|
||||
prompt: `你是 team "${teamName}" 的 EXECUTOR (${agentName})。
|
||||
你的 agent 名称是 "${agentName}",任务发现时用此名称匹配 owner。
|
||||
|
||||
当你收到 QARUN-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=executor --agent-name=${agentName}") 执行。
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 owner 为 "${agentName}" 的 QARUN-* 前缀任务
|
||||
- 所有输出必须带 [executor] 标识前缀
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
工作流程:
|
||||
1. TaskList → 找到 owner === "${agentName}" 的 QARUN-* 任务
|
||||
2. Skill(skill="team-quality-assurance", args="--role=executor --agent-name=${agentName}") 执行
|
||||
3. team_msg log + SendMessage
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
description: `Spawn executor worker`,
|
||||
team_name: teamName,
|
||||
name: "executor",
|
||||
prompt: `你是 team "${teamName}" 的 EXECUTOR。
|
||||
|
||||
当你收到 QARUN-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=executor") 执行。
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 QARUN-* 前缀的任务
|
||||
- 所有输出必须带 [executor] 标识前缀
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
工作流程:
|
||||
1. TaskList → 找到 QARUN-* 任务
|
||||
2. Skill(skill="team-quality-assurance", args="--role=executor") 执行
|
||||
3. team_msg log + SendMessage
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
}
|
||||
|
||||
// Analyst
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
description: `Spawn analyst worker`,
|
||||
team_name: teamName,
|
||||
name: "analyst",
|
||||
prompt: `你是 team "${teamName}" 的 ANALYST。
|
||||
|
||||
当你收到 QAANA-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=analyst") 执行。
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 QAANA-* 前缀的任务
|
||||
- 所有输出必须带 [analyst] 标识前缀
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
工作流程:
|
||||
1. TaskList → 找到 QAANA-* 任务
|
||||
2. Skill(skill="team-quality-assurance", args="--role=analyst") 执行
|
||||
3. team_msg log + SendMessage
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Unknown --role value | Error with available role list |
|
||||
| Missing --role arg | Error with usage hint |
|
||||
| Role file not found | Error with expected path (roles/{name}/role.md) |
|
||||
| Missing --role arg | Orchestration Mode -> auto route to coordinator |
|
||||
| Role file not found | Error with expected path (roles/<name>/role.md) |
|
||||
| Task prefix conflict | Log warning, proceed |
|
||||
| Coverage never reaches target | After 3 GC loops, accept current with warning |
|
||||
| Scout finds no issues | Report clean scan, skip to testing mode |
|
||||
|
||||
@@ -1,38 +1,32 @@
|
||||
# Role: analyst
|
||||
# Analyst Role
|
||||
|
||||
质量分析师。分析缺陷模式、覆盖率差距、测试有效性,生成综合质量报告。维护缺陷模式数据库,为 scout 和 strategist 提供反馈数据。
|
||||
Quality analyst. Analyze defect patterns, coverage gaps, test effectiveness, and generate comprehensive quality reports. Maintain defect pattern database and provide feedback data for scout and strategist.
|
||||
|
||||
## Role Identity
|
||||
## Identity
|
||||
|
||||
- **Name**: `analyst`
|
||||
- **Name**: `analyst` | **Tag**: `[analyst]`
|
||||
- **Task Prefix**: `QAANA-*`
|
||||
- **Responsibility**: Read-only analysis(质量分析)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[analyst]`
|
||||
- **Responsibility**: Read-only analysis (quality analysis)
|
||||
|
||||
## Role Boundaries
|
||||
## Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `QAANA-*` 前缀的任务
|
||||
- 所有输出必须带 `[analyst]` 标识
|
||||
- 基于数据生成分析报告
|
||||
- 更新 shared memory 中的缺陷模式和质量分数
|
||||
- Only process `QAANA-*` prefixed tasks
|
||||
- All output (SendMessage, team_msg, logs) must carry `[analyst]` identifier
|
||||
- Only communicate with coordinator via SendMessage
|
||||
- Generate analysis reports based on data
|
||||
- Update defect patterns and quality score in shared memory
|
||||
- Work strictly within quality analysis responsibility scope
|
||||
|
||||
### MUST NOT
|
||||
- Execute work outside this role's responsibility scope
|
||||
- Modify source code or test code
|
||||
- Execute tests
|
||||
- Communicate directly with other worker roles (must go through coordinator)
|
||||
- Create tasks for other roles (TaskCreate is coordinator-exclusive)
|
||||
- Omit `[analyst]` identifier in any output
|
||||
|
||||
- ❌ 修改源代码或测试代码
|
||||
- ❌ 执行测试
|
||||
- ❌ 为其他角色创建任务
|
||||
- ❌ 直接与其他 worker 通信
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `analysis_ready` | analyst → coordinator | 分析完成 | 包含质量评分 |
|
||||
| `quality_report` | analyst → coordinator | 报告生成 | 包含详细分析 |
|
||||
| `error` | analyst → coordinator | 分析失败 | 阻塞性错误 |
|
||||
---
|
||||
|
||||
## Toolbox
|
||||
|
||||
@@ -40,279 +34,143 @@
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `quality-report` | [commands/quality-report.md](commands/quality-report.md) | Phase 3 | 缺陷模式分析 + 覆盖率分析 |
|
||||
| `quality-report` | [commands/quality-report.md](commands/quality-report.md) | Phase 3 | Defect pattern + coverage analysis |
|
||||
|
||||
### CLI Capabilities
|
||||
### Tool Capabilities
|
||||
|
||||
| CLI Tool | Mode | Used By | Purpose |
|
||||
|----------|------|---------|---------|
|
||||
| `gemini` | analysis | quality-report.md | 缺陷模式识别和趋势分析 |
|
||||
| Tool | Type | Used By | Purpose |
|
||||
|------|------|---------|---------|
|
||||
| `gemini` | CLI | quality-report.md | Defect pattern recognition and trend analysis |
|
||||
|
||||
---
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `analysis_ready` | analyst -> coordinator | Analysis complete | Contains quality score |
|
||||
| `quality_report` | analyst -> coordinator | Report generated | Contains detailed analysis |
|
||||
| `error` | analyst -> coordinator | Analysis failed | Blocking error |
|
||||
|
||||
## Message Bus
|
||||
|
||||
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "quality-assurance",
|
||||
from: "analyst",
|
||||
to: "coordinator",
|
||||
type: <message-type>,
|
||||
summary: "[analyst] quality score: <score>/100, defect patterns: <count>, coverage: <coverage>%",
|
||||
ref: <report-path>
|
||||
})
|
||||
```
|
||||
|
||||
**CLI fallback** (when MCP unavailable):
|
||||
|
||||
```
|
||||
Bash("ccw team log --team quality-assurance --from analyst --to coordinator --type <message-type> --summary \"[analyst] analysis complete\" --ref <report-path> --json")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('QAANA-') &&
|
||||
t.owner === 'analyst' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
|
||||
|
||||
if (myTasks.length === 0) return
|
||||
const task = TaskGet({ taskId: myTasks[0].id })
|
||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||
```
|
||||
Standard task discovery flow: TaskList -> filter by prefix `QAANA-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
|
||||
|
||||
### Phase 2: Context Loading
|
||||
|
||||
```javascript
|
||||
// 读取 shared memory 获取所有数据
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1] || '.'
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
**Loading steps**:
|
||||
|
||||
const discoveredIssues = sharedMemory.discovered_issues || []
|
||||
const strategy = sharedMemory.test_strategy || {}
|
||||
const generatedTests = sharedMemory.generated_tests || {}
|
||||
const executionResults = sharedMemory.execution_results || {}
|
||||
const historicalPatterns = sharedMemory.defect_patterns || []
|
||||
1. Extract session path from task description
|
||||
2. Read shared memory to get all accumulated data
|
||||
|
||||
// 读取覆盖率数据
|
||||
let coverageData = null
|
||||
try {
|
||||
coverageData = JSON.parse(Read('coverage/coverage-summary.json'))
|
||||
} catch {}
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Shared memory | <session-folder>/shared-memory.json | Yes |
|
||||
| Discovered issues | sharedMemory.discovered_issues | No |
|
||||
| Test strategy | sharedMemory.test_strategy | No |
|
||||
| Generated tests | sharedMemory.generated_tests | No |
|
||||
| Execution results | sharedMemory.execution_results | No |
|
||||
| Historical patterns | sharedMemory.defect_patterns | No |
|
||||
|
||||
// 读取测试执行日志
|
||||
const runResults = {}
|
||||
try {
|
||||
const resultFiles = Glob(`${sessionFolder}/results/run-*.json`)
|
||||
for (const f of resultFiles) {
|
||||
const data = JSON.parse(Read(f))
|
||||
runResults[data.layer] = data
|
||||
}
|
||||
} catch {}
|
||||
```
|
||||
3. Read coverage data from `coverage/coverage-summary.json` if available
|
||||
4. Read test execution logs from `<session-folder>/results/run-*.json`
|
||||
|
||||
### Phase 3: Multi-Dimensional Analysis
|
||||
|
||||
```javascript
|
||||
// Read commands/quality-report.md for full implementation
|
||||
Read("commands/quality-report.md")
|
||||
```
|
||||
Delegate to `commands/quality-report.md` if available, otherwise execute inline.
|
||||
|
||||
**分析维度**:
|
||||
**Analysis Dimensions**:
|
||||
|
||||
```javascript
|
||||
const analysis = {
|
||||
// 1. 缺陷模式分析
|
||||
defect_patterns: analyzeDefectPatterns(discoveredIssues, executionResults),
|
||||
| Dimension | Description |
|
||||
|-----------|-------------|
|
||||
| Defect Patterns | Group issues by type, identify recurring patterns |
|
||||
| Coverage Gaps | Compare actual vs target coverage per layer |
|
||||
| Test Effectiveness | Evaluate test generation and execution results |
|
||||
| Quality Trend | Analyze coverage history over time |
|
||||
| Quality Score | Calculate comprehensive score (0-100) |
|
||||
|
||||
// 2. 覆盖率差距分析
|
||||
coverage_gaps: analyzeCoverageGaps(coverageData, strategy),
|
||||
**Defect Pattern Analysis**:
|
||||
- Group issues by perspective/type
|
||||
- Identify patterns with >= 2 occurrences
|
||||
- Record pattern type, count, affected files
|
||||
|
||||
// 3. 测试有效性分析
|
||||
test_effectiveness: analyzeTestEffectiveness(generatedTests, executionResults),
|
||||
**Coverage Gap Analysis**:
|
||||
- Compare total coverage vs layer targets
|
||||
- Record gaps: layer, target, actual, gap percentage
|
||||
|
||||
// 4. 质量趋势
|
||||
quality_trend: analyzeQualityTrend(sharedMemory.coverage_history || []),
|
||||
**Test Effectiveness Analysis**:
|
||||
- Files generated, pass rate, iterations needed
|
||||
- Effective if pass_rate >= 95%
|
||||
|
||||
// 5. 综合质量评分
|
||||
quality_score: 0
|
||||
}
|
||||
**Quality Score Calculation**:
|
||||
|
||||
function analyzeDefectPatterns(issues, results) {
|
||||
// 按类型分组
|
||||
const byType = {}
|
||||
for (const issue of issues) {
|
||||
const type = issue.perspective || 'unknown'
|
||||
if (!byType[type]) byType[type] = []
|
||||
byType[type].push(issue)
|
||||
}
|
||||
|
||||
// 识别重复模式
|
||||
const patterns = []
|
||||
for (const [type, typeIssues] of Object.entries(byType)) {
|
||||
if (typeIssues.length >= 2) {
|
||||
patterns.push({
|
||||
type,
|
||||
count: typeIssues.length,
|
||||
files: [...new Set(typeIssues.map(i => i.file))],
|
||||
description: `${type} 类问题在 ${typeIssues.length} 处重复出现`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return { by_type: byType, patterns, total: issues.length }
|
||||
}
|
||||
|
||||
function analyzeCoverageGaps(coverage, strategy) {
|
||||
if (!coverage) return { status: 'no_data' }
|
||||
|
||||
const gaps = []
|
||||
const totalCoverage = coverage.total?.lines?.pct || 0
|
||||
|
||||
// 对比策略目标
|
||||
for (const layer of (strategy.layers || [])) {
|
||||
const actual = totalCoverage
|
||||
if (actual < layer.target_coverage) {
|
||||
gaps.push({
|
||||
layer: layer.level,
|
||||
target: layer.target_coverage,
|
||||
actual,
|
||||
gap: layer.target_coverage - actual,
|
||||
files_below_target: [] // 可以进一步分析
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return { total_coverage: totalCoverage, gaps }
|
||||
}
|
||||
|
||||
function analyzeTestEffectiveness(generated, results) {
|
||||
const effectiveness = {}
|
||||
for (const [layer, data] of Object.entries(generated)) {
|
||||
const result = results[layer] || {}
|
||||
effectiveness[layer] = {
|
||||
files_generated: data.files?.length || 0,
|
||||
pass_rate: result.pass_rate || 0,
|
||||
iterations_needed: result.iterations || 0,
|
||||
effective: (result.pass_rate || 0) >= 95
|
||||
}
|
||||
}
|
||||
return effectiveness
|
||||
}
|
||||
|
||||
function analyzeQualityTrend(history) {
|
||||
if (history.length < 2) return { trend: 'insufficient_data' }
|
||||
const latest = history[history.length - 1]
|
||||
const previous = history[history.length - 2]
|
||||
const delta = (latest?.coverage || 0) - (previous?.coverage || 0)
|
||||
return {
|
||||
trend: delta > 0 ? 'improving' : delta < 0 ? 'declining' : 'stable',
|
||||
delta,
|
||||
data_points: history.length
|
||||
}
|
||||
}
|
||||
|
||||
// 综合质量评分 (0-100)
|
||||
function calculateQualityScore(analysis) {
|
||||
let score = 100
|
||||
|
||||
// 扣分项
|
||||
const criticalIssues = (analysis.defect_patterns.by_type?.security || []).length
|
||||
score -= criticalIssues * 10
|
||||
|
||||
const highIssues = (analysis.defect_patterns.by_type?.bug || []).length
|
||||
score -= highIssues * 5
|
||||
|
||||
// 覆盖率不达标扣分
|
||||
for (const gap of (analysis.coverage_gaps.gaps || [])) {
|
||||
score -= gap.gap * 0.5
|
||||
}
|
||||
|
||||
// 测试有效性加分
|
||||
const effectiveLayers = Object.values(analysis.test_effectiveness)
|
||||
.filter(e => e.effective).length
|
||||
score += effectiveLayers * 5
|
||||
|
||||
return Math.max(0, Math.min(100, Math.round(score)))
|
||||
}
|
||||
|
||||
analysis.quality_score = calculateQualityScore(analysis)
|
||||
```
|
||||
| Factor | Impact |
|
||||
|--------|--------|
|
||||
| Critical issues (security) | -10 per issue |
|
||||
| High issues (bug) | -5 per issue |
|
||||
| Coverage gap | -0.5 per gap percentage |
|
||||
| Effective test layers | +5 per layer |
|
||||
|
||||
### Phase 4: Report Generation
|
||||
|
||||
```javascript
|
||||
// 生成质量报告
|
||||
const reportContent = `# Quality Assurance Report
|
||||
**Report Structure**:
|
||||
1. Quality Score (0-100)
|
||||
2. Defect Pattern Analysis (total issues, recurring patterns)
|
||||
3. Coverage Analysis (overall coverage, gaps by layer)
|
||||
4. Test Effectiveness (per layer stats)
|
||||
5. Quality Trend (improving/declining/stable)
|
||||
6. Recommendations (based on score range)
|
||||
|
||||
## Quality Score: ${analysis.quality_score}/100
|
||||
**Score-based Recommendations**:
|
||||
|
||||
## 1. Defect Pattern Analysis
|
||||
- Total issues found: ${analysis.defect_patterns.total}
|
||||
- Recurring patterns: ${analysis.defect_patterns.patterns.length}
|
||||
${analysis.defect_patterns.patterns.map(p => ` - **${p.type}**: ${p.count} occurrences across ${p.files.length} files`).join('\n')}
|
||||
| Score Range | Recommendation |
|
||||
|-------------|----------------|
|
||||
| >= 80 | Quality is GOOD. Continue with current testing strategy. |
|
||||
| 60-79 | Quality needs IMPROVEMENT. Focus on coverage gaps and recurring patterns. |
|
||||
| < 60 | Quality is CONCERNING. Recommend deep scan and comprehensive test generation. |
|
||||
|
||||
## 2. Coverage Analysis
|
||||
- Overall coverage: ${analysis.coverage_gaps.total_coverage || 'N/A'}%
|
||||
- Coverage gaps: ${(analysis.coverage_gaps.gaps || []).length}
|
||||
${(analysis.coverage_gaps.gaps || []).map(g => ` - **${g.layer}**: target ${g.target}% vs actual ${g.actual}% (gap: ${g.gap}%)`).join('\n')}
|
||||
Write report to `<session-folder>/analysis/quality-report.md`.
|
||||
|
||||
## 3. Test Effectiveness
|
||||
${Object.entries(analysis.test_effectiveness).map(([layer, data]) =>
|
||||
`- **${layer}**: ${data.files_generated} files, pass rate ${data.pass_rate}%, ${data.iterations_needed} fix iterations`
|
||||
).join('\n')}
|
||||
|
||||
## 4. Quality Trend
|
||||
- Trend: ${analysis.quality_trend.trend}
|
||||
${analysis.quality_trend.delta !== undefined ? `- Coverage change: ${analysis.quality_trend.delta > 0 ? '+' : ''}${analysis.quality_trend.delta}%` : ''}
|
||||
|
||||
## 5. Recommendations
|
||||
${analysis.quality_score >= 80 ? '- Quality is GOOD. Continue with current testing strategy.' : ''}
|
||||
${analysis.quality_score >= 60 && analysis.quality_score < 80 ? '- Quality needs IMPROVEMENT. Focus on coverage gaps and recurring patterns.' : ''}
|
||||
${analysis.quality_score < 60 ? '- Quality is CONCERNING. Recommend deep scan and comprehensive test generation.' : ''}
|
||||
${analysis.defect_patterns.patterns.length > 0 ? `- Address ${analysis.defect_patterns.patterns.length} recurring defect patterns` : ''}
|
||||
${(analysis.coverage_gaps.gaps || []).length > 0 ? `- Close ${analysis.coverage_gaps.gaps.length} coverage gaps` : ''}
|
||||
`
|
||||
|
||||
Bash(`mkdir -p "${sessionFolder}/analysis"`)
|
||||
Write(`${sessionFolder}/analysis/quality-report.md`, reportContent)
|
||||
|
||||
// 更新 shared memory
|
||||
sharedMemory.defect_patterns = analysis.defect_patterns.patterns
|
||||
sharedMemory.quality_score = analysis.quality_score
|
||||
sharedMemory.coverage_history = sharedMemory.coverage_history || []
|
||||
sharedMemory.coverage_history.push({
|
||||
date: new Date().toISOString(),
|
||||
coverage: analysis.coverage_gaps.total_coverage || 0,
|
||||
quality_score: analysis.quality_score,
|
||||
issues: analysis.defect_patterns.total
|
||||
})
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
```
|
||||
Update shared memory:
|
||||
- `defect_patterns`: identified patterns
|
||||
- `quality_score`: calculated score
|
||||
- `coverage_history`: append new data point
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "analyst",
|
||||
to: "coordinator",
|
||||
type: "quality_report",
|
||||
summary: `[analyst] 质量评分: ${analysis.quality_score}/100, 缺陷模式: ${analysis.defect_patterns.patterns.length}, 覆盖率: ${analysis.coverage_gaps.total_coverage || 'N/A'}%`,
|
||||
ref: `${sessionFolder}/analysis/quality-report.md`
|
||||
})
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [analyst] Quality Analysis Results
|
||||
Standard report flow: team_msg log -> SendMessage with `[analyst]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Quality Score**: ${analysis.quality_score}/100
|
||||
**Defect Patterns**: ${analysis.defect_patterns.patterns.length} recurring
|
||||
**Coverage**: ${analysis.coverage_gaps.total_coverage || 'N/A'}%
|
||||
**Trend**: ${analysis.quality_trend.trend}
|
||||
|
||||
### Report
|
||||
${sessionFolder}/analysis/quality-report.md`,
|
||||
summary: `[analyst] QAANA complete: score ${analysis.quality_score}/100`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('QAANA-') && t.owner === 'analyst' &&
|
||||
t.status === 'pending' && t.blockedBy.length === 0
|
||||
)
|
||||
if (nextTasks.length > 0) { /* back to Phase 1 */ }
|
||||
```
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
|
||||
@@ -1,241 +1,194 @@
|
||||
# Role: coordinator
|
||||
# Coordinator Role
|
||||
|
||||
QA 团队协调者。编排 pipeline:需求澄清 → 模式选择 → 团队创建 → 任务分发 → 监控协调 → 质量门控 → 结果汇报。
|
||||
Orchestrate the Quality Assurance workflow: requirement clarification, mode selection, team creation, task dispatch, progress monitoring, quality gate control, and result reporting.
|
||||
|
||||
## Role Identity
|
||||
## Identity
|
||||
|
||||
- **Name**: `coordinator`
|
||||
- **Task Prefix**: N/A (coordinator creates tasks, doesn't receive them)
|
||||
- **Responsibility**: Orchestration
|
||||
- **Communication**: SendMessage to all teammates
|
||||
- **Output Tag**: `[coordinator]`
|
||||
- **Name**: `coordinator` | **Tag**: `[coordinator]`
|
||||
- **Responsibility**: Parse requirements -> Create team -> Dispatch tasks -> Monitor progress -> Report results
|
||||
|
||||
## Role Boundaries
|
||||
## Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 所有输出(SendMessage、team_msg、日志)必须带 `[coordinator]` 标识
|
||||
- 仅负责需求澄清、模式选择、任务创建/分发、进度监控、质量门控、结果汇报
|
||||
- 通过 TaskCreate 创建任务并分配给 worker 角色
|
||||
- 通过消息总线监控 worker 进度并路由消息
|
||||
- All output (SendMessage, team_msg, logs) must carry `[coordinator]` identifier
|
||||
- Only responsible for requirement clarification, mode selection, task creation/dispatch, progress monitoring, quality gate control, and result reporting
|
||||
- Create tasks via TaskCreate and assign to worker roles
|
||||
- Monitor worker progress via message bus and route messages
|
||||
|
||||
### MUST NOT
|
||||
- Directly execute any business tasks (scanning, testing, analysis, etc.)
|
||||
- Directly invoke implementation subagents (cli-explore-agent, code-developer, etc.)
|
||||
- Directly modify source code or generated artifact files
|
||||
- Bypass worker roles to complete delegated work
|
||||
- Omit `[coordinator]` identifier in any output
|
||||
|
||||
- ❌ **直接执行任何业务任务**(扫描、测试、分析等)
|
||||
- ❌ 直接调用 cli-explore-agent、code-developer 等实现类 subagent
|
||||
- ❌ 直接修改源代码或生成产物文件
|
||||
- ❌ 绕过 worker 角色自行完成应委派的工作
|
||||
- ❌ 在输出中省略 `[coordinator]` 标识
|
||||
> **Core principle**: coordinator is the orchestrator, not the executor. All actual work must be delegated to worker roles via TaskCreate.
|
||||
|
||||
> **核心原则**: coordinator 是指挥者,不是执行者。所有实际工作必须通过 TaskCreate 委派给 worker 角色。
|
||||
---
|
||||
|
||||
## Message Types
|
||||
## Entry Router
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `mode_selected` | coordinator → all | QA 模式确定 | Discovery/Testing/Full |
|
||||
| `gc_loop_trigger` | coordinator → generator | 覆盖率不达标 | 触发 Generator-Executor 循环 |
|
||||
| `quality_gate` | coordinator → user | 质量评估 | 通过/不通过/有条件通过 |
|
||||
| `task_unblocked` | coordinator → worker | 依赖解除 | 任务可执行 |
|
||||
| `error` | coordinator → user | 协调错误 | 阻塞性问题 |
|
||||
| `shutdown` | coordinator → all | 团队关闭 | 清理资源 |
|
||||
When coordinator is invoked, first detect the invocation type:
|
||||
|
||||
## Toolbox
|
||||
| Detection | Condition | Handler |
|
||||
|-----------|-----------|---------|
|
||||
| Worker callback | Message contains `[role-name]` tag from a known worker role | -> handleCallback: auto-advance pipeline |
|
||||
| Status check | Arguments contain "check" or "status" | -> handleCheck: output execution graph, no advancement |
|
||||
| Manual resume | Arguments contain "resume" or "continue" | -> handleResume: check worker states, advance pipeline |
|
||||
| New session | None of the above | -> Phase 0 (Session Resume Check) |
|
||||
|
||||
### Available Commands
|
||||
For callback/check/resume: load `commands/monitor.md` and execute the appropriate handler, then STOP.
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `dispatch` | [commands/dispatch.md](commands/dispatch.md) | Phase 3 | 任务链创建与依赖管理 |
|
||||
| `monitor` | [commands/monitor.md](commands/monitor.md) | Phase 4 | 消息总线轮询与协调循环 |
|
||||
---
|
||||
|
||||
### Subagent Capabilities
|
||||
## Phase 0: Session Resume Check
|
||||
|
||||
> Coordinator 不直接使用 subagent(通过 worker 角色间接使用)
|
||||
**Objective**: Detect and resume interrupted sessions before creating new ones.
|
||||
|
||||
### CLI Capabilities
|
||||
**Workflow**:
|
||||
1. Scan session directory for sessions with status "active" or "paused"
|
||||
2. No sessions found -> proceed to Phase 1
|
||||
3. Single session found -> resume it (-> Session Reconciliation)
|
||||
4. Multiple sessions -> AskUserQuestion for user selection
|
||||
|
||||
> Coordinator 不直接使用 CLI 分析工具
|
||||
**Session Reconciliation**:
|
||||
1. Audit TaskList -> get real status of all tasks
|
||||
2. Reconcile: session state <-> TaskList status (bidirectional sync)
|
||||
3. Reset any in_progress tasks -> pending (they were interrupted)
|
||||
4. Determine remaining pipeline from reconciled state
|
||||
5. Rebuild team if disbanded (TeamCreate + spawn needed workers only)
|
||||
6. Create missing tasks with correct blockedBy dependencies
|
||||
7. Verify dependency chain integrity
|
||||
8. Update session file with reconciled state
|
||||
9. Kick first executable task's worker -> Phase 4
|
||||
|
||||
## Execution
|
||||
---
|
||||
|
||||
### Phase 1: Requirement Clarification
|
||||
## Phase 1: Requirement Clarification
|
||||
|
||||
```javascript
|
||||
const args = "$ARGUMENTS"
|
||||
**Objective**: Parse user input and gather execution parameters.
|
||||
|
||||
// 提取任务描述
|
||||
const taskDescription = args.replace(/--role[=\s]+\w+/, '').replace(/--team[=\s]+[\w-]+/, '').replace(/--mode[=\s]+\w+/, '').trim()
|
||||
**Workflow**:
|
||||
|
||||
// QA 模式选择
|
||||
function detectQAMode(args, desc) {
|
||||
const modeMatch = args.match(/--mode[=\s]+(discovery|testing|full)/)
|
||||
if (modeMatch) return modeMatch[1]
|
||||
if (/发现|扫描|scan|discover|issue|问题/.test(desc)) return 'discovery'
|
||||
if (/测试|test|覆盖|coverage|TDD/.test(desc)) return 'testing'
|
||||
return 'full'
|
||||
}
|
||||
1. **Parse arguments** for explicit settings: mode, scope, focus areas
|
||||
|
||||
let qaMode = detectQAMode(args, taskDescription)
|
||||
2. **QA Mode Selection**:
|
||||
|
||||
// ★ 统一 auto mode 检测:-y/--yes 从 $ARGUMENTS 或 ccw 传播
|
||||
const autoYes = /\b(-y|--yes)\b/.test(args)
|
||||
| Condition | Mode |
|
||||
|-----------|------|
|
||||
| Explicit `--mode=discovery` flag | discovery |
|
||||
| Explicit `--mode=testing` flag | testing |
|
||||
| Explicit `--mode=full` flag | full |
|
||||
| Task description contains: discovery/scan/issue keywords | discovery |
|
||||
| Task description contains: test/coverage/TDD keywords | testing |
|
||||
| No explicit flag and no keyword match | full (default) |
|
||||
|
||||
// 简单任务可跳过确认(auto 模式跳过)
|
||||
if (!autoYes && (!taskDescription || taskDescription.length < 10)) {
|
||||
const clarification = AskUserQuestion({
|
||||
questions: [{
|
||||
question: "请描述 QA 目标(哪些模块需要质量保障?关注哪些方面?)",
|
||||
header: "QA Target",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "自定义", description: "输入具体描述" },
|
||||
{ label: "全项目扫描", description: "对整个项目进行多视角质量扫描" },
|
||||
{ label: "变更测试", description: "针对最近代码变更生成和执行测试" },
|
||||
{ label: "完整QA流程", description: "扫描+测试+分析的完整闭环" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
3. **Ask for missing parameters** via AskUserQuestion (skip in auto mode with -y/--yes flag):
|
||||
|
||||
| Question | Options |
|
||||
|----------|---------|
|
||||
| QA Target description | Custom input / Full project scan / Change testing / Complete QA flow |
|
||||
|
||||
**Success**: All parameters captured, mode finalized.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Create Team + Initialize Session
|
||||
|
||||
**Objective**: Initialize team, session file, and shared memory.
|
||||
|
||||
**Workflow**:
|
||||
1. Generate session ID
|
||||
2. Create session folder
|
||||
3. Call TeamCreate with team name
|
||||
4. Initialize shared-memory.json with empty fields
|
||||
5. Initialize wisdom directory (learnings.md, decisions.md, conventions.md, issues.md)
|
||||
6. Write session file with: session_id, mode, scope, status="active"
|
||||
|
||||
**Shared Memory Structure**:
|
||||
```
|
||||
{
|
||||
"discovered_issues": [],
|
||||
"test_strategy": {},
|
||||
"generated_tests": {},
|
||||
"execution_results": {},
|
||||
"defect_patterns": [],
|
||||
"coverage_history": [],
|
||||
"quality_score": null
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 2: Create Team + Initialize Session
|
||||
**Success**: Team created, session file written, shared memory initialized.
|
||||
|
||||
```javascript
|
||||
const teamName = "quality-assurance"
|
||||
const sessionSlug = taskDescription.slice(0, 30).replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '-')
|
||||
const sessionDate = new Date().toISOString().slice(0, 10)
|
||||
const sessionFolder = `.workflow/.team/QA-${sessionSlug}-${sessionDate}`
|
||||
Bash(`mkdir -p "${sessionFolder}"`)
|
||||
---
|
||||
|
||||
// 初始化 shared memory
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify({
|
||||
discovered_issues: [],
|
||||
test_strategy: {},
|
||||
generated_tests: {},
|
||||
execution_results: {},
|
||||
defect_patterns: [],
|
||||
coverage_history: [],
|
||||
quality_score: null
|
||||
}, null, 2))
|
||||
## Phase 3: Create Task Chain
|
||||
|
||||
TeamCreate({ team_name: teamName })
|
||||
**Objective**: Dispatch tasks based on mode with proper dependencies.
|
||||
|
||||
// ⚠️ Workers are NOT pre-spawned here.
|
||||
// Workers are spawned per-stage in Phase 4 via Stop-Wait Task(run_in_background: false).
|
||||
// See SKILL.md Coordinator Spawn Template for worker prompt templates.
|
||||
// Worker roles: Scout, Strategist, Generator, Executor, Analyst
|
||||
```
|
||||
Delegate to `commands/dispatch.md` which creates the full task chain.
|
||||
|
||||
### Phase 3: Create Task Chain
|
||||
**Pipeline by Mode**:
|
||||
|
||||
根据 qaMode 创建不同的任务链:
|
||||
| Mode | Pipeline |
|
||||
|------|----------|
|
||||
| Discovery | SCOUT-001 -> QASTRAT-001 -> QAGEN-001 -> QARUN-001 -> QAANA-001 |
|
||||
| Testing | QASTRAT-001 -> QAGEN-001(L1) -> QARUN-001(L1) -> QAGEN-002(L2) -> QARUN-002(L2) -> QAANA-001 |
|
||||
| Full QA | SCOUT-001 -> QASTRAT-001 -> [QAGEN-001(L1) + QAGEN-002(L2)](parallel) -> [QARUN-001 + QARUN-002](parallel) -> QAANA-001 -> SCOUT-002(regression) |
|
||||
|
||||
```javascript
|
||||
// Read commands/dispatch.md for full implementation
|
||||
Read("commands/dispatch.md")
|
||||
```
|
||||
---
|
||||
|
||||
**Discovery Mode**:
|
||||
```
|
||||
SCOUT-001 → QASTRAT-001 → QAGEN-001 → QARUN-001 → QAANA-001
|
||||
```
|
||||
## Phase 4: Coordination Loop
|
||||
|
||||
**Testing Mode** (跳过 scout):
|
||||
```
|
||||
QASTRAT-001 → QAGEN-001(L1) → QARUN-001(L1) → QAGEN-002(L2) → QARUN-002(L2) → QAANA-001
|
||||
```
|
||||
**Objective**: Spawn workers, monitor progress, advance pipeline.
|
||||
|
||||
**Full QA Mode**:
|
||||
```
|
||||
SCOUT-001 → QASTRAT-001 → [QAGEN-001(L1) + QAGEN-002(L2)](parallel) → [QARUN-001 + QARUN-002](parallel) → QAANA-001 → SCOUT-002(回归)
|
||||
```
|
||||
> **Design principle (Stop-Wait)**: Model execution has no time concept. No polling with sleep.
|
||||
> - Use synchronous `Task(run_in_background: false)` calls
|
||||
> - Worker return = stage completion signal
|
||||
|
||||
### Phase 4: Coordination Loop
|
||||
Delegate to `commands/monitor.md` for full implementation.
|
||||
|
||||
> **设计原则(Stop-Wait)**: 模型执行没有时间概念,禁止任何形式的轮询等待。
|
||||
> - ❌ 禁止: `while` 循环 + `sleep` + 检查状态
|
||||
> - ✅ 采用: 同步 `Task(run_in_background: false)` 调用,Worker 返回 = 阶段完成信号
|
||||
>
|
||||
> 按 Phase 3 创建的任务链顺序,逐阶段 spawn worker 同步执行。
|
||||
> Worker prompt 使用 SKILL.md Coordinator Spawn Template。
|
||||
|
||||
```javascript
|
||||
// Read commands/monitor.md for full implementation
|
||||
Read("commands/monitor.md")
|
||||
```
|
||||
**Message Handling**:
|
||||
|
||||
| Received Message | Action |
|
||||
|-----------------|--------|
|
||||
| `scan_ready` | 标记 SCOUT complete → 解锁 QASTRAT |
|
||||
| `strategy_ready` | 标记 QASTRAT complete → 解锁 QAGEN |
|
||||
| `tests_generated` | 标记 QAGEN complete → 解锁 QARUN |
|
||||
| `tests_passed` | 标记 QARUN complete → 解锁 QAANA 或下一层 |
|
||||
| `tests_failed` | 评估覆盖率 → 触发 GC 循环(gc_loop_trigger)或继续 |
|
||||
| `analysis_ready` | 标记 QAANA complete → 评估质量门控 |
|
||||
| Worker: `error` | 评估严重性 → 重试或上报用户 |
|
||||
| `scan_ready` | Mark SCOUT complete -> unlock QASTRAT |
|
||||
| `strategy_ready` | Mark QASTRAT complete -> unlock QAGEN |
|
||||
| `tests_generated` | Mark QAGEN complete -> unlock QARUN |
|
||||
| `tests_passed` | Mark QARUN complete -> unlock QAANA or next layer |
|
||||
| `tests_failed` | Evaluate coverage -> trigger GC loop (gc_loop_trigger) or continue |
|
||||
| `analysis_ready` | Mark QAANA complete -> evaluate quality gate |
|
||||
| Worker: `error` | Evaluate severity -> retry or report to user |
|
||||
|
||||
**GC 循环触发逻辑**:
|
||||
```javascript
|
||||
if (coverage < targetCoverage && gcIteration < 3) {
|
||||
// 创建 QAGEN-fix 任务 → QARUN 重新执行
|
||||
gcIteration++
|
||||
} else if (gcIteration >= 3) {
|
||||
// 接受当前覆盖率,继续流水线
|
||||
team_msg({ type: "quality_gate", data: { status: "CONDITIONAL", coverage } })
|
||||
}
|
||||
```
|
||||
**GC Loop Trigger Logic**:
|
||||
|
||||
### Phase 5: Report + Persist
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| coverage < targetCoverage AND gcIteration < 3 | Create QAGEN-fix task -> QARUN re-execute, gcIteration++ |
|
||||
| gcIteration >= 3 | Accept current coverage, continue pipeline, team_msg quality_gate CONDITIONAL |
|
||||
|
||||
```javascript
|
||||
// 读取 shared memory 汇总结果
|
||||
const memory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
|
||||
---
|
||||
|
||||
const report = {
|
||||
mode: qaMode,
|
||||
issues_found: memory.discovered_issues?.length || 0,
|
||||
test_strategy: memory.test_strategy?.layers || [],
|
||||
tests_generated: Object.keys(memory.generated_tests || {}).length,
|
||||
pass_rate: memory.execution_results?.pass_rate || 0,
|
||||
coverage: memory.execution_results?.coverage || 0,
|
||||
quality_score: memory.quality_score || 'N/A',
|
||||
defect_patterns: memory.defect_patterns?.length || 0
|
||||
}
|
||||
## Phase 5: Report + Persist
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "coordinator",
|
||||
to: "user", type: "quality_gate",
|
||||
summary: `[coordinator] QA完成: ${report.issues_found}个问题, 覆盖率${report.coverage}%, 质量分${report.quality_score}`
|
||||
})
|
||||
**Objective**: Completion report and follow-up options.
|
||||
|
||||
SendMessage({
|
||||
content: `## [coordinator] Quality Assurance Report\n\n${JSON.stringify(report, null, 2)}`,
|
||||
summary: `[coordinator] QA report: ${report.quality_score}`
|
||||
})
|
||||
**Workflow**:
|
||||
1. Load session state -> count completed tasks, duration
|
||||
2. Read shared memory for summary
|
||||
3. List deliverables with output paths
|
||||
4. Update session status -> "completed"
|
||||
5. Log via team_msg
|
||||
6. SendMessage report to user
|
||||
7. Offer next steps to user (skip in auto mode)
|
||||
|
||||
// 询问下一步(auto 模式跳过,默认关闭团队)
|
||||
if (!autoYes) {
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "QA 流程已完成。下一步:",
|
||||
header: "Next",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "新目标", description: "对新模块/需求执行QA" },
|
||||
{ label: "深入分析", description: "对发现的问题进行更深入分析" },
|
||||
{ label: "关闭团队", description: "关闭所有 teammate 并清理" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Teammate unresponsive | Send follow-up, 2x → respawn |
|
||||
| Teammate unresponsive | Send follow-up, 2x -> respawn |
|
||||
| Scout finds nothing | Skip to testing mode |
|
||||
| GC loop stuck >3 iterations | Accept current coverage, continue pipeline |
|
||||
| Test environment broken | Notify user, suggest manual fix |
|
||||
|
||||
@@ -1,39 +1,32 @@
|
||||
# Role: executor
|
||||
# Executor Role
|
||||
|
||||
测试执行者。运行测试套件,收集覆盖率数据,在测试失败时进行自动修复循环。实现 Generator-Executor(GC)循环中的执行端。
|
||||
Test executor. Run test suites, collect coverage data, and perform automatic fix cycles when tests fail. Implement the execution side of the Generator-Executor (GC) loop.
|
||||
|
||||
## Role Identity
|
||||
## Identity
|
||||
|
||||
- **Name**: `executor`
|
||||
- **Name**: `executor` | **Tag**: `[executor]`
|
||||
- **Task Prefix**: `QARUN-*`
|
||||
- **Responsibility**: Validation(测试执行与修复)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[executor]`
|
||||
- **Responsibility**: Validation (test execution and fix)
|
||||
|
||||
## Role Boundaries
|
||||
## Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `QARUN-*` 前缀的任务
|
||||
- 所有输出必须带 `[executor]` 标识
|
||||
- 执行测试并收集覆盖率
|
||||
- 在失败时尝试自动修复
|
||||
- Only process `QARUN-*` prefixed tasks
|
||||
- All output (SendMessage, team_msg, logs) must carry `[executor]` identifier
|
||||
- Only communicate with coordinator via SendMessage
|
||||
- Execute tests and collect coverage
|
||||
- Attempt automatic fix on failure
|
||||
- Work strictly within test execution responsibility scope
|
||||
|
||||
### MUST NOT
|
||||
- Execute work outside this role's responsibility scope
|
||||
- Generate new tests from scratch (that's generator's responsibility)
|
||||
- Modify source code (unless fixing tests themselves)
|
||||
- Communicate directly with other worker roles (must go through coordinator)
|
||||
- Create tasks for other roles (TaskCreate is coordinator-exclusive)
|
||||
- Omit `[executor]` identifier in any output
|
||||
|
||||
- ❌ 从零生成新测试(那是 generator 的职责)
|
||||
- ❌ 修改源代码(除非修复测试本身)
|
||||
- ❌ 为其他角色创建任务
|
||||
- ❌ 直接与其他 worker 通信
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `tests_passed` | executor → coordinator | 所有测试通过 | 包含覆盖率数据 |
|
||||
| `tests_failed` | executor → coordinator | 测试失败 | 包含失败详情和修复尝试 |
|
||||
| `coverage_report` | executor → coordinator | 覆盖率收集完成 | 覆盖率数据 |
|
||||
| `error` | executor → coordinator | 执行环境错误 | 阻塞性错误 |
|
||||
---
|
||||
|
||||
## Toolbox
|
||||
|
||||
@@ -41,208 +34,136 @@
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `run-fix-cycle` | [commands/run-fix-cycle.md](commands/run-fix-cycle.md) | Phase 3 | 迭代测试执行与自动修复 |
|
||||
| `run-fix-cycle` | [commands/run-fix-cycle.md](commands/run-fix-cycle.md) | Phase 3 | Iterative test execution and auto-fix |
|
||||
|
||||
### Subagent Capabilities
|
||||
### Tool Capabilities
|
||||
|
||||
| Agent Type | Used By | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `code-developer` | run-fix-cycle.md | 测试失败自动修复 |
|
||||
| Tool | Type | Used By | Purpose |
|
||||
|------|------|---------|---------|
|
||||
| `code-developer` | subagent | run-fix-cycle.md | Test failure auto-fix |
|
||||
|
||||
---
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `tests_passed` | executor -> coordinator | All tests pass | Contains coverage data |
|
||||
| `tests_failed` | executor -> coordinator | Tests fail | Contains failure details and fix attempts |
|
||||
| `coverage_report` | executor -> coordinator | Coverage collected | Coverage data |
|
||||
| `error` | executor -> coordinator | Execution environment error | Blocking error |
|
||||
|
||||
## Message Bus
|
||||
|
||||
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "quality-assurance",
|
||||
from: "executor",
|
||||
to: "coordinator",
|
||||
type: <message-type>,
|
||||
summary: "[executor] <layer>: <status-message>",
|
||||
ref: <results-file>,
|
||||
data: { pass_rate, coverage, iterations }
|
||||
})
|
||||
```
|
||||
|
||||
**CLI fallback** (when MCP unavailable):
|
||||
|
||||
```
|
||||
Bash("ccw team log --team quality-assurance --from executor --to coordinator --type <message-type> --summary \"[executor] test execution complete\" --ref <results-file> --json")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
// Parse agent name for parallel instances (e.g., executor-1, executor-2)
|
||||
const agentNameMatch = args.match(/--agent-name[=\s]+([\w-]+)/)
|
||||
const agentName = agentNameMatch ? agentNameMatch[1] : 'executor'
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
|
||||
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('QARUN-') &&
|
||||
t.owner === agentName &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
Standard task discovery flow: TaskList -> filter by prefix `QARUN-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
|
||||
|
||||
if (myTasks.length === 0) return
|
||||
const task = TaskGet({ taskId: myTasks[0].id })
|
||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||
```
|
||||
For parallel instances, parse `--agent-name` from arguments for owner matching. Falls back to `executor` for single-instance execution.
|
||||
|
||||
### Phase 2: Environment Detection
|
||||
|
||||
```javascript
|
||||
// 读取 shared memory
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1] || '.'
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
**Detection steps**:
|
||||
|
||||
const strategy = sharedMemory.test_strategy || {}
|
||||
const generatedTests = sharedMemory.generated_tests || {}
|
||||
const targetLayer = task.description.match(/layer:\s*(L[123])/)?.[1] || 'L1'
|
||||
1. Extract session path from task description
|
||||
2. Read shared memory for strategy and generated tests
|
||||
|
||||
// 检测测试命令
|
||||
function detectTestCommand(framework, layer) {
|
||||
const commands = {
|
||||
'jest': `npx jest --coverage --testPathPattern="${layer === 'L1' ? 'unit' : layer === 'L2' ? 'integration' : 'e2e'}"`,
|
||||
'vitest': `npx vitest run --coverage --reporter=json`,
|
||||
'pytest': `python -m pytest --cov --cov-report=json`,
|
||||
'mocha': `npx mocha --reporter json`,
|
||||
}
|
||||
return commands[framework] || 'npm test -- --coverage'
|
||||
}
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Shared memory | <session-folder>/shared-memory.json | Yes |
|
||||
| Test strategy | sharedMemory.test_strategy | Yes |
|
||||
| Generated tests | sharedMemory.generated_tests | Yes |
|
||||
| Target layer | task description | Yes |
|
||||
|
||||
const testCommand = detectTestCommand(strategy.test_framework || 'vitest', targetLayer)
|
||||
3. Detect test command based on framework:
|
||||
|
||||
// 获取变更的测试文件
|
||||
const testFiles = generatedTests[targetLayer]?.files || []
|
||||
```
|
||||
| Framework | Command Pattern |
|
||||
|-----------|-----------------|
|
||||
| jest | `npx jest --coverage --testPathPattern="<layer>"` |
|
||||
| vitest | `npx vitest run --coverage --reporter=json` |
|
||||
| pytest | `python -m pytest --cov --cov-report=json` |
|
||||
| mocha | `npx mocha --reporter json` |
|
||||
| unknown | `npm test -- --coverage` |
|
||||
|
||||
4. Get changed test files from generated_tests[targetLayer].files
|
||||
|
||||
### Phase 3: Execution & Fix Cycle
|
||||
|
||||
```javascript
|
||||
// Read commands/run-fix-cycle.md for full implementation
|
||||
Read("commands/run-fix-cycle.md")
|
||||
```
|
||||
Delegate to `commands/run-fix-cycle.md` if available, otherwise execute inline.
|
||||
|
||||
**核心逻辑**: 迭代执行测试,失败时自动修复
|
||||
**Iterative Test-Fix Cycle**:
|
||||
|
||||
```javascript
|
||||
let iteration = 0
|
||||
const MAX_ITERATIONS = 5
|
||||
let lastResult = null
|
||||
let passRate = 0
|
||||
let coverage = 0
|
||||
| Step | Action |
|
||||
|------|--------|
|
||||
| 1 | Run test command |
|
||||
| 2 | Parse results -> check pass rate |
|
||||
| 3 | Pass rate >= 95% -> exit loop (success) |
|
||||
| 4 | Extract failing test details |
|
||||
| 5 | Delegate fix to code-developer subagent |
|
||||
| 6 | Increment iteration counter |
|
||||
| 7 | iteration >= MAX (5) -> exit loop (report failures) |
|
||||
| 8 | Go to Step 1 |
|
||||
|
||||
while (iteration < MAX_ITERATIONS) {
|
||||
// 执行测试
|
||||
lastResult = Bash(`${testCommand} 2>&1 || true`)
|
||||
|
||||
// 解析结果
|
||||
const testsPassed = (lastResult.match(/(\d+) passed/)?.[1] || 0) * 1
|
||||
const testsFailed = (lastResult.match(/(\d+) failed/)?.[1] || 0) * 1
|
||||
const testsTotal = testsPassed + testsFailed
|
||||
passRate = testsTotal > 0 ? (testsPassed / testsTotal * 100) : 0
|
||||
|
||||
// 解析覆盖率
|
||||
try {
|
||||
const coverageJson = JSON.parse(Read('coverage/coverage-summary.json'))
|
||||
coverage = coverageJson.total?.lines?.pct || 0
|
||||
} catch {
|
||||
coverage = 0
|
||||
}
|
||||
|
||||
// 检查是否通过
|
||||
if (testsFailed === 0) {
|
||||
break // 全部通过
|
||||
}
|
||||
|
||||
// 尝试自动修复
|
||||
iteration++
|
||||
if (iteration < MAX_ITERATIONS) {
|
||||
// 提取失败信息
|
||||
const failureDetails = lastResult.split('\n')
|
||||
.filter(l => /FAIL|Error|AssertionError|Expected|Received/.test(l))
|
||||
.slice(0, 20)
|
||||
.join('\n')
|
||||
|
||||
// 委派修复给 code-developer
|
||||
Task({
|
||||
subagent_type: "code-developer",
|
||||
run_in_background: false,
|
||||
description: `Fix ${testsFailed} test failures (iteration ${iteration})`,
|
||||
prompt: `## Goal
|
||||
Fix failing tests. Do NOT modify source code, only fix test files.
|
||||
|
||||
## Test Failures
|
||||
${failureDetails}
|
||||
|
||||
## Test Files
|
||||
${testFiles.map(f => `- ${f}`).join('\n')}
|
||||
|
||||
## Instructions
|
||||
- Read failing test files
|
||||
- Fix assertions, imports, or test setup
|
||||
- Do NOT change source code
|
||||
- Do NOT skip/ignore tests`
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
**Fix Agent Prompt Structure**:
|
||||
- Goal: Fix failing tests
|
||||
- Constraint: Do NOT modify source code, only fix test files
|
||||
- Input: Failure details, test file list
|
||||
- Instructions: Read failing tests, fix assertions/imports/setup, do NOT skip/ignore tests
|
||||
|
||||
### Phase 4: Result Analysis
|
||||
|
||||
```javascript
|
||||
const resultData = {
|
||||
layer: targetLayer,
|
||||
iterations: iteration,
|
||||
pass_rate: passRate,
|
||||
coverage: coverage,
|
||||
tests_passed: lastResult?.match(/(\d+) passed/)?.[1] || 0,
|
||||
tests_failed: lastResult?.match(/(\d+) failed/)?.[1] || 0,
|
||||
all_passed: passRate === 100 || (lastResult && !lastResult.includes('FAIL'))
|
||||
}
|
||||
**Analyze test outcomes**:
|
||||
|
||||
// 保存执行结果
|
||||
Bash(`mkdir -p "${sessionFolder}/results"`)
|
||||
Write(`${sessionFolder}/results/run-${targetLayer}.json`, JSON.stringify(resultData, null, 2))
|
||||
| Metric | Source | Threshold |
|
||||
|--------|--------|-----------|
|
||||
| Pass rate | Test output parser | >= 95% |
|
||||
| Coverage | Coverage tool output | Per layer target |
|
||||
| Flaky tests | Compare runs | 0 flaky |
|
||||
|
||||
// 更新 shared memory
|
||||
sharedMemory.execution_results = sharedMemory.execution_results || {}
|
||||
sharedMemory.execution_results[targetLayer] = resultData
|
||||
sharedMemory.execution_results.pass_rate = passRate
|
||||
sharedMemory.execution_results.coverage = coverage
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
```
|
||||
**Result Data Structure**:
|
||||
- layer, iterations, pass_rate, coverage
|
||||
- tests_passed, tests_failed, all_passed
|
||||
|
||||
Save results to `<session-folder>/results/run-<layer>.json`.
|
||||
|
||||
Update shared memory with `execution_results` field.
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const statusMsg = resultData.all_passed
|
||||
? `全部通过 (${resultData.tests_passed} tests, 覆盖率 ${coverage}%)`
|
||||
: `${resultData.tests_failed} 个失败 (${iteration}次修复尝试, 覆盖率 ${coverage}%)`
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
|
||||
|
||||
const msgType = resultData.all_passed ? 'tests_passed' : 'tests_failed'
|
||||
Standard report flow: team_msg log -> SendMessage with `[executor]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "executor",
|
||||
to: "coordinator",
|
||||
type: msgType,
|
||||
summary: `[executor] ${targetLayer}: ${statusMsg}`,
|
||||
ref: `${sessionFolder}/results/run-${targetLayer}.json`,
|
||||
data: { pass_rate: passRate, coverage, iterations: iteration }
|
||||
})
|
||||
Message type selection: `tests_passed` if all_passed, else `tests_failed`.
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [executor] Test Execution Results
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Layer**: ${targetLayer}
|
||||
**Status**: ${resultData.all_passed ? 'PASS' : 'FAIL'}
|
||||
**Pass Rate**: ${passRate}%
|
||||
**Coverage**: ${coverage}%
|
||||
**Iterations**: ${iteration}/${MAX_ITERATIONS}
|
||||
|
||||
### Details
|
||||
- Tests passed: ${resultData.tests_passed}
|
||||
- Tests failed: ${resultData.tests_failed}`,
|
||||
summary: `[executor] QARUN ${targetLayer}: ${resultData.all_passed ? 'PASS' : 'FAIL'} ${passRate}%`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('QARUN-') && t.owner === agentName &&
|
||||
t.status === 'pending' && t.blockedBy.length === 0
|
||||
)
|
||||
if (nextTasks.length > 0) { /* back to Phase 1 */ }
|
||||
```
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
|
||||
@@ -1,38 +1,32 @@
|
||||
# Role: generator
|
||||
# Generator Role
|
||||
|
||||
测试用例生成器。按 strategist 制定的策略和层级,生成对应的测试代码。支持 L1 单元测试、L2 集成测试、L3 E2E 测试。遵循项目现有测试模式和框架约定。
|
||||
Test case generator. Generate test code according to strategist's strategy and layers. Support L1 unit tests, L2 integration tests, L3 E2E tests. Follow project's existing test patterns and framework conventions.
|
||||
|
||||
## Role Identity
|
||||
## Identity
|
||||
|
||||
- **Name**: `generator`
|
||||
- **Name**: `generator` | **Tag**: `[generator]`
|
||||
- **Task Prefix**: `QAGEN-*`
|
||||
- **Responsibility**: Code generation(测试代码生成)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[generator]`
|
||||
- **Responsibility**: Code generation (test code generation)
|
||||
|
||||
## Role Boundaries
|
||||
## Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `QAGEN-*` 前缀的任务
|
||||
- 所有输出必须带 `[generator]` 标识
|
||||
- 遵循项目现有测试框架和模式
|
||||
- 生成的测试必须可运行
|
||||
- Only process `QAGEN-*` prefixed tasks
|
||||
- All output (SendMessage, team_msg, logs) must carry `[generator]` identifier
|
||||
- Only communicate with coordinator via SendMessage
|
||||
- Follow project's existing test framework and patterns
|
||||
- Generated tests must be runnable
|
||||
- Work strictly within test code generation responsibility scope
|
||||
|
||||
### MUST NOT
|
||||
- Execute work outside this role's responsibility scope
|
||||
- Modify source code (only generate test code)
|
||||
- Execute tests
|
||||
- Communicate directly with other worker roles (must go through coordinator)
|
||||
- Create tasks for other roles (TaskCreate is coordinator-exclusive)
|
||||
- Omit `[generator]` identifier in any output
|
||||
|
||||
- ❌ 修改源代码(仅生成测试代码)
|
||||
- ❌ 执行测试
|
||||
- ❌ 为其他角色创建任务
|
||||
- ❌ 直接与其他 worker 通信
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `tests_generated` | generator → coordinator | 测试生成完成 | 包含生成的测试文件列表 |
|
||||
| `tests_revised` | generator → coordinator | 测试修订完成 | GC 循环中修订后 |
|
||||
| `error` | generator → coordinator | 生成失败 | 阻塞性错误 |
|
||||
---
|
||||
|
||||
## Toolbox
|
||||
|
||||
@@ -40,239 +34,129 @@
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `generate-tests` | [commands/generate-tests.md](commands/generate-tests.md) | Phase 3 | 按层级生成测试代码 |
|
||||
| `generate-tests` | [commands/generate-tests.md](commands/generate-tests.md) | Phase 3 | Layer-based test code generation |
|
||||
|
||||
### Subagent Capabilities
|
||||
### Tool Capabilities
|
||||
|
||||
| Agent Type | Used By | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `code-developer` | generate-tests.md | 复杂测试代码生成 |
|
||||
| Tool | Type | Used By | Purpose |
|
||||
|------|------|---------|---------|
|
||||
| `code-developer` | subagent | generate-tests.md | Complex test code generation |
|
||||
| `gemini` | CLI | generate-tests.md | Analyze existing test patterns |
|
||||
|
||||
### CLI Capabilities
|
||||
---
|
||||
|
||||
| CLI Tool | Mode | Used By | Purpose |
|
||||
|----------|------|---------|---------|
|
||||
| `gemini` | analysis | generate-tests.md | 分析现有测试模式 |
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `tests_generated` | generator -> coordinator | Test generation complete | Contains generated test file list |
|
||||
| `tests_revised` | generator -> coordinator | Test revision complete | After revision in GC loop |
|
||||
| `error` | generator -> coordinator | Generation failed | Blocking error |
|
||||
|
||||
## Message Bus
|
||||
|
||||
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "quality-assurance",
|
||||
from: "generator",
|
||||
to: "coordinator",
|
||||
type: <message-type>,
|
||||
summary: "[generator] <layer> test generation complete: <file-count> files",
|
||||
ref: <first-test-file>
|
||||
})
|
||||
```
|
||||
|
||||
**CLI fallback** (when MCP unavailable):
|
||||
|
||||
```
|
||||
Bash("ccw team log --team quality-assurance --from generator --to coordinator --type <message-type> --summary \"[generator] test generation complete\" --ref <test-file> --json")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
// Parse agent name for parallel instances (e.g., generator-1, generator-2)
|
||||
const agentNameMatch = args.match(/--agent-name[=\s]+([\w-]+)/)
|
||||
const agentName = agentNameMatch ? agentNameMatch[1] : 'generator'
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
|
||||
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('QAGEN-') &&
|
||||
t.owner === agentName &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
Standard task discovery flow: TaskList -> filter by prefix `QAGEN-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
|
||||
|
||||
if (myTasks.length === 0) return
|
||||
const task = TaskGet({ taskId: myTasks[0].id })
|
||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||
```
|
||||
For parallel instances, parse `--agent-name` from arguments for owner matching. Falls back to `generator` for single-instance execution.
|
||||
|
||||
### Phase 2: Strategy & Pattern Loading
|
||||
|
||||
```javascript
|
||||
// 读取 shared memory 获取策略
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1] || '.'
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
**Loading steps**:
|
||||
|
||||
const strategy = sharedMemory.test_strategy || {}
|
||||
const targetLayer = task.description.match(/layer:\s*(L[123])/)?.[1] || strategy.layers?.[0]?.level || 'L1'
|
||||
1. Extract session path from task description
|
||||
2. Read shared memory to get strategy
|
||||
|
||||
// 确定目标层级的详情
|
||||
const layerConfig = strategy.layers?.find(l => l.level === targetLayer) || {
|
||||
level: targetLayer,
|
||||
name: targetLayer === 'L1' ? 'Unit Tests' : targetLayer === 'L2' ? 'Integration Tests' : 'E2E Tests',
|
||||
target_coverage: targetLayer === 'L1' ? 80 : targetLayer === 'L2' ? 60 : 40,
|
||||
focus_files: []
|
||||
}
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Shared memory | <session-folder>/shared-memory.json | Yes |
|
||||
| Test strategy | sharedMemory.test_strategy | Yes |
|
||||
| Target layer | task description or strategy.layers[0] | Yes |
|
||||
|
||||
// 学习现有测试模式(找 3 个相似测试文件)
|
||||
const existingTests = Glob(`**/*.{test,spec}.{ts,tsx,js,jsx}`)
|
||||
const testPatterns = existingTests.slice(0, 3).map(f => ({
|
||||
path: f,
|
||||
content: Read(f)
|
||||
}))
|
||||
3. Determine target layer config:
|
||||
|
||||
// 检测测试框架和配置
|
||||
const testFramework = strategy.test_framework || 'vitest'
|
||||
```
|
||||
| Layer | Name | Coverage Target |
|
||||
|-------|------|-----------------|
|
||||
| L1 | Unit Tests | 80% |
|
||||
| L2 | Integration Tests | 60% |
|
||||
| L3 | E2E Tests | 40% |
|
||||
|
||||
4. Learn existing test patterns (find 3 similar test files)
|
||||
5. Detect test framework and configuration
|
||||
|
||||
### Phase 3: Test Generation
|
||||
|
||||
```javascript
|
||||
// Read commands/generate-tests.md for full implementation
|
||||
Read("commands/generate-tests.md")
|
||||
```
|
||||
Delegate to `commands/generate-tests.md` if available, otherwise execute inline.
|
||||
|
||||
**核心策略**: 基于复杂度选择生成方式
|
||||
**Implementation Strategy Selection**:
|
||||
|
||||
```javascript
|
||||
const focusFiles = layerConfig.focus_files || []
|
||||
| Focus File Count | Complexity | Strategy |
|
||||
|------------------|------------|----------|
|
||||
| <= 3 files | Low | Direct: inline Edit/Write |
|
||||
| 3-5 files | Medium | Single code-developer agent |
|
||||
| > 5 files | High | Batch by module, one agent per batch |
|
||||
|
||||
if (focusFiles.length <= 3) {
|
||||
// 直接生成:读取源文件 → 分析 → 写测试
|
||||
for (const sourceFile of focusFiles) {
|
||||
const sourceContent = Read(sourceFile)
|
||||
**Direct Generation Flow**:
|
||||
1. Read source file content
|
||||
2. Determine test file path (follow project convention)
|
||||
3. Check if test already exists -> supplement, else create new
|
||||
4. Generate test content based on source exports and existing patterns
|
||||
|
||||
// 确定测试文件路径(遵循项目约定)
|
||||
const testPath = sourceFile
|
||||
.replace(/\.(ts|tsx|js|jsx)$/, `.test.$1`)
|
||||
.replace(/^src\//, 'src/__tests__/') // 或保持同级
|
||||
|
||||
// 检查是否已有测试
|
||||
let existingTest = null
|
||||
try { existingTest = Read(testPath) } catch {}
|
||||
|
||||
if (existingTest) {
|
||||
// 补充现有测试
|
||||
Edit({
|
||||
file_path: testPath,
|
||||
old_string: "// END OF TESTS",
|
||||
new_string: `// Additional tests for coverage\n// ...new test cases...\n// END OF TESTS`
|
||||
})
|
||||
} else {
|
||||
// 创建新测试文件
|
||||
Write(testPath, generateTestContent(sourceFile, sourceContent, testPatterns, testFramework))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 委派给 code-developer
|
||||
Task({
|
||||
subagent_type: "code-developer",
|
||||
run_in_background: false,
|
||||
description: `Generate ${targetLayer} tests for ${focusFiles.length} files`,
|
||||
prompt: `## Goal
|
||||
Generate ${layerConfig.name} for the following source files.
|
||||
|
||||
## Test Framework
|
||||
${testFramework}
|
||||
|
||||
## Existing Test Patterns
|
||||
${testPatterns.map(t => `### ${t.path}\n\`\`\`\n${t.content.substring(0, 500)}\n\`\`\``).join('\n\n')}
|
||||
|
||||
## Source Files to Test
|
||||
${focusFiles.map(f => `- ${f}`).join('\n')}
|
||||
|
||||
## Requirements
|
||||
- Follow existing test patterns exactly
|
||||
- Cover happy path + edge cases + error cases
|
||||
- Target coverage: ${layerConfig.target_coverage}%
|
||||
- Do NOT modify source files, only create/modify test files`
|
||||
})
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
function generateTestContent(sourceFile, sourceContent, patterns, framework) {
|
||||
// 基于模式生成测试代码骨架
|
||||
const imports = extractExports(sourceContent)
|
||||
const pattern = patterns[0]?.content || ''
|
||||
|
||||
return `import { ${imports.join(', ')} } from '${sourceFile.replace(/\.(ts|tsx|js|jsx)$/, '')}'
|
||||
|
||||
describe('${sourceFile}', () => {
|
||||
${imports.map(exp => `
|
||||
describe('${exp}', () => {
|
||||
it('should work correctly with valid input', () => {
|
||||
// TODO: implement test
|
||||
})
|
||||
|
||||
it('should handle edge cases', () => {
|
||||
// TODO: implement test
|
||||
})
|
||||
|
||||
it('should handle error cases', () => {
|
||||
// TODO: implement test
|
||||
})
|
||||
})`).join('\n')}
|
||||
})`
|
||||
}
|
||||
|
||||
function extractExports(content) {
|
||||
const matches = content.match(/export\s+(function|const|class|interface|type)\s+(\w+)/g) || []
|
||||
return matches.map(m => m.split(/\s+/).pop())
|
||||
}
|
||||
```
|
||||
**Test Content Generation**:
|
||||
- Import source exports
|
||||
- Create describe blocks per export
|
||||
- Include happy path, edge cases, error cases tests
|
||||
|
||||
### Phase 4: Self-Validation
|
||||
|
||||
```javascript
|
||||
// 验证生成的测试文件语法正确
|
||||
const generatedTests = Bash(`git diff --name-only`).split('\n')
|
||||
.filter(f => /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(f))
|
||||
**Validation Checks**:
|
||||
|
||||
// TypeScript 语法检查
|
||||
const syntaxResult = Bash(`npx tsc --noEmit ${generatedTests.join(' ')} 2>&1 || true`)
|
||||
const hasSyntaxErrors = syntaxResult.includes('error TS')
|
||||
| Check | Method | Pass Criteria |
|
||||
|-------|--------|---------------|
|
||||
| Syntax | TypeScript check | No errors |
|
||||
| File existence | Verify all planned files exist | All files present |
|
||||
| Import resolution | Check no broken imports | All imports resolve |
|
||||
|
||||
if (hasSyntaxErrors) {
|
||||
// 自动修复语法错误
|
||||
const errors = syntaxResult.split('\n').filter(l => l.includes('error TS'))
|
||||
for (const error of errors.slice(0, 5)) {
|
||||
// 解析错误并尝试修复
|
||||
}
|
||||
}
|
||||
If validation fails -> attempt auto-fix (max 2 attempts) -> report remaining issues.
|
||||
|
||||
// 记录生成的测试
|
||||
const generatedTestInfo = {
|
||||
layer: targetLayer,
|
||||
files: generatedTests,
|
||||
count: generatedTests.length,
|
||||
syntax_clean: !hasSyntaxErrors
|
||||
}
|
||||
|
||||
// 更新 shared memory
|
||||
sharedMemory.generated_tests = sharedMemory.generated_tests || {}
|
||||
sharedMemory.generated_tests[targetLayer] = generatedTestInfo
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
```
|
||||
Update shared memory with `generated_tests` field for this layer.
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const msgType = task.subject.includes('fix') ? 'tests_revised' : 'tests_generated'
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "generator",
|
||||
to: "coordinator",
|
||||
type: msgType,
|
||||
summary: `[generator] ${targetLayer} 测试生成完成: ${generatedTests.length} 文件, 语法${hasSyntaxErrors ? '有错误' : '正常'}`,
|
||||
ref: generatedTests[0]
|
||||
})
|
||||
Standard report flow: team_msg log -> SendMessage with `[generator]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [generator] Test Generation Results
|
||||
Message type selection: `tests_generated` for new generation, `tests_revised` for fix iterations.
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Layer**: ${targetLayer} - ${layerConfig.name}
|
||||
**Generated**: ${generatedTests.length} test files
|
||||
**Syntax**: ${hasSyntaxErrors ? 'ERRORS' : 'CLEAN'}
|
||||
|
||||
### Generated Files
|
||||
${generatedTests.map(f => `- ${f}`).join('\n')}`,
|
||||
summary: `[generator] QAGEN complete: ${targetLayer} ${generatedTests.length} files`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('QAGEN-') && t.owner === agentName &&
|
||||
t.status === 'pending' && t.blockedBy.length === 0
|
||||
)
|
||||
if (nextTasks.length > 0) { /* back to Phase 1 */ }
|
||||
```
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
|
||||
@@ -1,36 +1,31 @@
|
||||
# Role: strategist
|
||||
# Strategist Role
|
||||
|
||||
测试策略师。分析变更范围,确定测试层级(L1-L3),定义覆盖率目标,生成测试策略文档。基于 scout 发现的问题和代码变更制定针对性测试计划。
|
||||
Test strategist. Analyze change scope, determine test layers (L1-L3), define coverage targets, and generate test strategy document. Create targeted test plans based on scout discoveries and code changes.
|
||||
|
||||
## Role Identity
|
||||
## Identity
|
||||
|
||||
- **Name**: `strategist`
|
||||
- **Name**: `strategist` | **Tag**: `[strategist]`
|
||||
- **Task Prefix**: `QASTRAT-*`
|
||||
- **Responsibility**: Orchestration(策略制定)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[strategist]`
|
||||
- **Responsibility**: Orchestration (strategy formulation)
|
||||
|
||||
## Role Boundaries
|
||||
## Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `QASTRAT-*` 前缀的任务
|
||||
- 所有输出必须带 `[strategist]` 标识
|
||||
- 仅通过 SendMessage 与 coordinator 通信
|
||||
- Only process `QASTRAT-*` prefixed tasks
|
||||
- All output (SendMessage, team_msg, logs) must carry `[strategist]` identifier
|
||||
- Only communicate with coordinator via SendMessage
|
||||
- Work strictly within strategy formulation responsibility scope
|
||||
|
||||
### MUST NOT
|
||||
- Execute work outside this role's responsibility scope
|
||||
- Write test code
|
||||
- Execute tests
|
||||
- Communicate directly with other worker roles (must go through coordinator)
|
||||
- Create tasks for other roles (TaskCreate is coordinator-exclusive)
|
||||
- Modify source code
|
||||
- Omit `[strategist]` identifier in any output
|
||||
|
||||
- ❌ 编写测试代码
|
||||
- ❌ 执行测试
|
||||
- ❌ 为其他角色创建任务
|
||||
- ❌ 修改源代码
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `strategy_ready` | strategist → coordinator | 策略制定完成 | 包含层级选择和覆盖率目标 |
|
||||
| `error` | strategist → coordinator | 策略制定失败 | 阻塞性错误 |
|
||||
---
|
||||
|
||||
## Toolbox
|
||||
|
||||
@@ -38,222 +33,125 @@
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `analyze-scope` | [commands/analyze-scope.md](commands/analyze-scope.md) | Phase 2-3 | 变更范围分析 + 策略制定 |
|
||||
| `analyze-scope` | [commands/analyze-scope.md](commands/analyze-scope.md) | Phase 2-3 | Change scope analysis + strategy formulation |
|
||||
|
||||
### Subagent Capabilities
|
||||
### Tool Capabilities
|
||||
|
||||
| Agent Type | Used By | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `cli-explore-agent` | analyze-scope.md | 代码结构和依赖分析 |
|
||||
| Tool | Type | Used By | Purpose |
|
||||
|------|------|---------|---------|
|
||||
| `cli-explore-agent` | subagent | analyze-scope.md | Code structure and dependency analysis |
|
||||
| `gemini` | CLI | analyze-scope.md | Test strategy analysis |
|
||||
|
||||
### CLI Capabilities
|
||||
---
|
||||
|
||||
| CLI Tool | Mode | Used By | Purpose |
|
||||
|----------|------|---------|---------|
|
||||
| `gemini` | analysis | analyze-scope.md | 测试策略分析 |
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `strategy_ready` | strategist -> coordinator | Strategy complete | Contains layer selection and coverage targets |
|
||||
| `error` | strategist -> coordinator | Strategy failed | Blocking error |
|
||||
|
||||
## Message Bus
|
||||
|
||||
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
|
||||
|
||||
```
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: "quality-assurance",
|
||||
from: "strategist",
|
||||
to: "coordinator",
|
||||
type: <message-type>,
|
||||
summary: "[strategist] QASTRAT complete: <layers-summary>",
|
||||
ref: <artifact-path>
|
||||
})
|
||||
```
|
||||
|
||||
**CLI fallback** (when MCP unavailable):
|
||||
|
||||
```
|
||||
Bash("ccw team log --team quality-assurance --from strategist --to coordinator --type <message-type> --summary \"[strategist] QASTRAT complete\" --ref <artifact-path> --json")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('QASTRAT-') &&
|
||||
t.owner === 'strategist' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
|
||||
|
||||
if (myTasks.length === 0) return
|
||||
const task = TaskGet({ taskId: myTasks[0].id })
|
||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||
```
|
||||
Standard task discovery flow: TaskList -> filter by prefix `QASTRAT-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
|
||||
|
||||
### Phase 2: Context & Change Analysis
|
||||
|
||||
```javascript
|
||||
// 读取 shared memory 获取 scout 发现
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1] || '.'
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
**Loading steps**:
|
||||
|
||||
const discoveredIssues = sharedMemory.discovered_issues || []
|
||||
const historicalPatterns = sharedMemory.defect_patterns || []
|
||||
1. Extract session path from task description
|
||||
2. Read shared memory to get scout discoveries
|
||||
|
||||
// 分析变更范围
|
||||
const changedFiles = Bash(`git diff --name-only HEAD~5 2>/dev/null || git diff --name-only --cached 2>/dev/null || echo ""`)
|
||||
.split('\n').filter(Boolean)
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Shared memory | <session-folder>/shared-memory.json | Yes |
|
||||
| Discovered issues | sharedMemory.discovered_issues | No |
|
||||
| Defect patterns | sharedMemory.defect_patterns | No |
|
||||
|
||||
// 分类变更文件
|
||||
const fileCategories = {
|
||||
source: changedFiles.filter(f => /\.(ts|tsx|js|jsx|py|java|go|rs)$/.test(f)),
|
||||
test: changedFiles.filter(f => /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(f) || /test_/.test(f)),
|
||||
config: changedFiles.filter(f => /\.(json|yaml|yml|toml|env)$/.test(f)),
|
||||
style: changedFiles.filter(f => /\.(css|scss|less)$/.test(f))
|
||||
}
|
||||
3. Analyze change scope:
|
||||
|
||||
// 检测项目测试框架
|
||||
const testFramework = Bash(`ls package.json 2>/dev/null && (cat package.json | grep -o '"jest"\\|"vitest"\\|"mocha"\\|"pytest"' | head -1) || echo "unknown"`)
|
||||
.trim().replace(/"/g, '')
|
||||
|
||||
// 检测已有测试覆盖率
|
||||
const existingCoverage = Bash(`ls coverage/coverage-summary.json 2>/dev/null && cat coverage/coverage-summary.json | head -20 || echo "no coverage data"`)
|
||||
```
|
||||
Bash("git diff --name-only HEAD~5 2>/dev/null || git diff --name-only --cached 2>/dev/null || echo \"\"")
|
||||
```
|
||||
|
||||
4. Categorize changed files:
|
||||
|
||||
| Category | Pattern |
|
||||
|----------|---------|
|
||||
| Source | `/\.(ts|tsx|js|jsx|py|java|go|rs)$/` |
|
||||
| Test | `/\.(test|spec)\.(ts|tsx|js|jsx)$/` or `/test_/` |
|
||||
| Config | `/\.(json|yaml|yml|toml|env)$/` |
|
||||
| Style | `/\.(css|scss|less)$/` |
|
||||
|
||||
5. Detect test framework from project files
|
||||
6. Check existing coverage data if available
|
||||
|
||||
### Phase 3: Strategy Generation
|
||||
|
||||
```javascript
|
||||
// 基于变更范围和发现的问题制定策略
|
||||
const strategy = {
|
||||
scope: {
|
||||
total_changed: changedFiles.length,
|
||||
source_files: fileCategories.source.length,
|
||||
test_files: fileCategories.test.length,
|
||||
issue_count: discoveredIssues.length
|
||||
},
|
||||
test_framework: testFramework,
|
||||
layers: [],
|
||||
coverage_targets: {}
|
||||
}
|
||||
**Layer Selection Logic**:
|
||||
|
||||
// 层级选择逻辑
|
||||
if (fileCategories.source.length > 0) {
|
||||
strategy.layers.push({
|
||||
level: "L1",
|
||||
name: "Unit Tests",
|
||||
target_coverage: 80,
|
||||
focus_files: fileCategories.source,
|
||||
rationale: "所有变更的源文件需要单元测试覆盖"
|
||||
})
|
||||
}
|
||||
| Condition | Layer | Coverage Target |
|
||||
|-----------|-------|-----------------|
|
||||
| Has source file changes | L1: Unit Tests | 80% |
|
||||
| >= 3 source files OR critical issues found | L2: Integration Tests | 60% |
|
||||
| >= 3 critical/high severity issues | L3: E2E Tests | 40% |
|
||||
| No changes but has scout issues | L1 focused on issue files | 80% |
|
||||
|
||||
if (fileCategories.source.length >= 3 || discoveredIssues.some(i => i.severity === 'critical')) {
|
||||
strategy.layers.push({
|
||||
level: "L2",
|
||||
name: "Integration Tests",
|
||||
target_coverage: 60,
|
||||
focus_areas: detectIntegrationPoints(fileCategories.source),
|
||||
rationale: "多文件变更或关键问题需要集成测试"
|
||||
})
|
||||
}
|
||||
**Strategy Document Structure**:
|
||||
- Scope Analysis: changed files count, source files, scout issues, test framework
|
||||
- Test Layers: level, name, coverage target, focus files/areas, rationale
|
||||
- Priority Issues: top 10 issues from scout
|
||||
|
||||
if (discoveredIssues.filter(i => i.severity === 'critical' || i.severity === 'high').length >= 3) {
|
||||
strategy.layers.push({
|
||||
level: "L3",
|
||||
name: "E2E Tests",
|
||||
target_coverage: 40,
|
||||
focus_flows: detectUserFlows(discoveredIssues),
|
||||
rationale: "多个高优先级问题需要端到端验证"
|
||||
})
|
||||
}
|
||||
Write strategy document to `<session-folder>/strategy/test-strategy.md`.
|
||||
|
||||
// 如果没有变更但有 scout 发现,聚焦于发现的问题
|
||||
if (strategy.layers.length === 0 && discoveredIssues.length > 0) {
|
||||
strategy.layers.push({
|
||||
level: "L1",
|
||||
name: "Unit Tests",
|
||||
target_coverage: 80,
|
||||
focus_files: [...new Set(discoveredIssues.map(i => i.file))],
|
||||
rationale: "Scout 发现的问题需要测试覆盖"
|
||||
})
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
function detectIntegrationPoints(files) {
|
||||
// 检测模块间交互点
|
||||
return files.filter(f => /service|controller|handler|middleware|route/.test(f))
|
||||
}
|
||||
|
||||
function detectUserFlows(issues) {
|
||||
// 从问题中推断用户流程
|
||||
return [...new Set(issues.map(i => i.file.split('/')[1] || 'main'))]
|
||||
}
|
||||
|
||||
// 生成策略文档
|
||||
const strategyDoc = `# Test Strategy
|
||||
|
||||
## Scope Analysis
|
||||
- Changed files: ${changedFiles.length}
|
||||
- Source files: ${fileCategories.source.length}
|
||||
- Scout issues: ${discoveredIssues.length}
|
||||
- Test framework: ${testFramework}
|
||||
|
||||
## Test Layers
|
||||
${strategy.layers.map(l => `### ${l.level}: ${l.name}
|
||||
- Coverage target: ${l.target_coverage}%
|
||||
- Focus: ${l.focus_files?.join(', ') || l.focus_areas?.join(', ') || l.focus_flows?.join(', ')}
|
||||
- Rationale: ${l.rationale}`).join('\n\n')}
|
||||
|
||||
## Priority Issues
|
||||
${discoveredIssues.slice(0, 10).map(i => `- [${i.severity}] ${i.file}:${i.line} - ${i.description}`).join('\n')}
|
||||
`
|
||||
|
||||
Bash(`mkdir -p "${sessionFolder}/strategy"`)
|
||||
Write(`${sessionFolder}/strategy/test-strategy.md`, strategyDoc)
|
||||
|
||||
// 更新 shared memory
|
||||
sharedMemory.test_strategy = strategy
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
```
|
||||
Update shared memory with `test_strategy` field.
|
||||
|
||||
### Phase 4: Strategy Validation
|
||||
|
||||
```javascript
|
||||
// 验证策略合理性
|
||||
const validationChecks = {
|
||||
has_layers: strategy.layers.length > 0,
|
||||
has_targets: strategy.layers.every(l => l.target_coverage > 0),
|
||||
covers_issues: discoveredIssues.length === 0 ||
|
||||
discoveredIssues.some(i => strategy.layers.some(l =>
|
||||
l.focus_files?.includes(i.file)
|
||||
)),
|
||||
framework_detected: testFramework !== 'unknown'
|
||||
}
|
||||
**Validation Checks**:
|
||||
|
||||
const isValid = Object.values(validationChecks).every(Boolean)
|
||||
```
|
||||
| Check | Criteria |
|
||||
|-------|----------|
|
||||
| has_layers | strategy.layers.length > 0 |
|
||||
| has_targets | All layers have target_coverage > 0 |
|
||||
| covers_issues | Discovered issues covered by focus_files |
|
||||
| framework_detected | testFramework !== 'unknown' |
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const layersSummary = strategy.layers.map(l => `${l.level}(${l.target_coverage}%)`).join(', ')
|
||||
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "strategist",
|
||||
to: "coordinator",
|
||||
type: "strategy_ready",
|
||||
summary: `[strategist] 策略就绪: ${layersSummary}, 框架: ${testFramework}`,
|
||||
ref: `${sessionFolder}/strategy/test-strategy.md`
|
||||
})
|
||||
Standard report flow: team_msg log -> SendMessage with `[strategist]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [strategist] Test Strategy Ready
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Layers**: ${layersSummary}
|
||||
**Framework**: ${testFramework}
|
||||
|
||||
### Layer Details
|
||||
${strategy.layers.map(l => `- **${l.level}**: ${l.name} (target: ${l.target_coverage}%, ${l.focus_files?.length || '?'} files)`).join('\n')}
|
||||
|
||||
### Strategy Document
|
||||
${sessionFolder}/strategy/test-strategy.md`,
|
||||
summary: `[strategist] QASTRAT complete: ${layersSummary}`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('QASTRAT-') && t.owner === 'strategist' &&
|
||||
t.status === 'pending' && t.blockedBy.length === 0
|
||||
)
|
||||
if (nextTasks.length > 0) { /* back to Phase 1 */ }
|
||||
```
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
|
||||
Reference in New Issue
Block a user