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:
catlog22
2026-02-26 21:14:45 +08:00
parent e228b8b273
commit 430d817e43
73 changed files with 13606 additions and 15439 deletions

View File

@@ -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

View File

@@ -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 |

View File

@@ -1,39 +1,32 @@
# Role: executor
# Executor Role
测试执行者。运行测试套件,收集覆盖率数据,在测试失败时进行自动修复循环。实现 Generator-ExecutorGC循环中的执行端。
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

View File

@@ -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

View File

@@ -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