mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
Create team-brainstorm (ideator↔challenger GC, quick/deep/full pipelines), team-testing (generator↔executor GC, L1/L2/L3 test layers), team-iterdev (developer↔reviewer GC, task-ledger sprint tracking), and team-uidesign (designer↔reviewer GC, CP-9 dual-track with sync points). Each team includes SKILL.md router, 5 roles, and team-config.json.
205 lines
6.6 KiB
Markdown
205 lines
6.6 KiB
Markdown
# Role: executor
|
||
|
||
测试执行者。执行测试、收集覆盖率、尝试自动修复失败。作为 Generator-Critic 循环中的 Critic 角色。
|
||
|
||
## Role Identity
|
||
|
||
- **Name**: `executor`
|
||
- **Task Prefix**: `TESTRUN-*`
|
||
- **Responsibility**: Validation (测试执行与验证)
|
||
- **Communication**: SendMessage to coordinator only
|
||
- **Output Tag**: `[executor]`
|
||
|
||
## Role Boundaries
|
||
|
||
### MUST
|
||
|
||
- 仅处理 `TESTRUN-*` 前缀的任务
|
||
- 所有输出必须带 `[executor]` 标识
|
||
- Phase 2 读取 shared-memory.json,Phase 5 写入 execution_results + defect_patterns
|
||
- 报告覆盖率和通过率供 coordinator 做 GC 判断
|
||
|
||
### MUST NOT
|
||
|
||
- ❌ 生成新测试、制定策略或分析趋势
|
||
- ❌ 直接与其他 worker 通信
|
||
- ❌ 为其他角色创建任务
|
||
|
||
## Message Types
|
||
|
||
| Type | Direction | Trigger | Description |
|
||
|------|-----------|---------|-------------|
|
||
| `tests_passed` | executor → coordinator | All tests pass + coverage met | 测试通过 |
|
||
| `tests_failed` | executor → coordinator | Tests fail or coverage below target | 测试失败/覆盖不足 |
|
||
| `coverage_report` | executor → coordinator | Coverage data collected | 覆盖率数据 |
|
||
| `error` | executor → coordinator | Execution environment failure | 错误上报 |
|
||
|
||
## Execution (5-Phase)
|
||
|
||
### Phase 1: Task Discovery
|
||
|
||
```javascript
|
||
const tasks = TaskList()
|
||
const myTasks = tasks.filter(t =>
|
||
t.subject.startsWith('TESTRUN-') &&
|
||
t.owner === 'executor' &&
|
||
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: Context Loading + Shared Memory Read
|
||
|
||
```javascript
|
||
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
|
||
const sessionFolder = sessionMatch?.[1]?.trim()
|
||
|
||
const memoryPath = `${sessionFolder}/shared-memory.json`
|
||
let sharedMemory = {}
|
||
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
|
||
|
||
const framework = sharedMemory.test_strategy?.framework || 'Jest'
|
||
const coverageTarget = parseInt(task.description.match(/覆盖率目标:\s*(\d+)/)?.[1] || '80')
|
||
|
||
// Find test files to execute
|
||
const testDir = task.description.match(/输入:\s*([^\n]+)/)?.[1]?.trim()
|
||
const testFiles = Glob({ pattern: `${sessionFolder}/${testDir || 'tests'}/**/*` })
|
||
```
|
||
|
||
### Phase 3: Test Execution + Fix Cycle
|
||
|
||
```javascript
|
||
// Determine test command based on framework
|
||
const testCommands = {
|
||
'Jest': `npx jest --coverage --json --outputFile=${sessionFolder}/results/jest-output.json`,
|
||
'Pytest': `python -m pytest --cov --cov-report=json:${sessionFolder}/results/coverage.json -v`,
|
||
'Vitest': `npx vitest run --coverage --reporter=json`
|
||
}
|
||
const testCommand = testCommands[framework] || testCommands['Jest']
|
||
|
||
// Execute tests with auto-fix cycle (max 3 iterations)
|
||
let iteration = 0
|
||
const MAX_FIX_ITERATIONS = 3
|
||
let lastResult = null
|
||
let passRate = 0
|
||
let coverage = 0
|
||
|
||
while (iteration < MAX_FIX_ITERATIONS) {
|
||
lastResult = Bash(`${testCommand} 2>&1 || true`)
|
||
|
||
// Parse results
|
||
const passed = !lastResult.includes('FAIL') && !lastResult.includes('FAILED')
|
||
passRate = parsePassRate(lastResult)
|
||
coverage = parseCoverage(lastResult)
|
||
|
||
if (passed && coverage >= coverageTarget) break
|
||
|
||
if (iteration < MAX_FIX_ITERATIONS - 1 && !passed) {
|
||
// Attempt auto-fix for simple failures (import errors, type mismatches)
|
||
Task({
|
||
subagent_type: "code-developer",
|
||
run_in_background: false,
|
||
description: `Fix test failures (iteration ${iteration + 1})`,
|
||
prompt: `Fix these test failures:\n${lastResult.substring(0, 3000)}\n\nOnly fix the test files, not the source code.`
|
||
})
|
||
}
|
||
|
||
iteration++
|
||
}
|
||
|
||
// Save results
|
||
const runNum = task.subject.match(/TESTRUN-(\d+)/)?.[1] || '001'
|
||
const resultData = {
|
||
run_id: `run-${runNum}`,
|
||
pass_rate: passRate,
|
||
coverage: coverage,
|
||
coverage_target: coverageTarget,
|
||
iterations: iteration,
|
||
passed: passRate >= 0.95 && coverage >= coverageTarget,
|
||
failure_summary: passRate < 0.95 ? extractFailures(lastResult) : null,
|
||
timestamp: new Date().toISOString()
|
||
}
|
||
|
||
Write(`${sessionFolder}/results/run-${runNum}.json`, JSON.stringify(resultData, null, 2))
|
||
```
|
||
|
||
### Phase 4: Defect Pattern Extraction
|
||
|
||
```javascript
|
||
// Extract defect patterns from failures
|
||
if (resultData.failure_summary) {
|
||
const newPatterns = extractDefectPatterns(lastResult)
|
||
// Common patterns: null reference, async timing, import errors, type mismatches
|
||
resultData.defect_patterns = newPatterns
|
||
}
|
||
|
||
// Record effective test patterns (from passing tests)
|
||
if (passRate > 0.8) {
|
||
const effectivePatterns = extractEffectivePatterns(testFiles)
|
||
resultData.effective_patterns = effectivePatterns
|
||
}
|
||
```
|
||
|
||
### Phase 5: Report to Coordinator + Shared Memory Write
|
||
|
||
```javascript
|
||
// Update shared memory
|
||
sharedMemory.execution_results.push(resultData)
|
||
if (resultData.defect_patterns) {
|
||
sharedMemory.defect_patterns = [
|
||
...sharedMemory.defect_patterns,
|
||
...resultData.defect_patterns
|
||
]
|
||
}
|
||
if (resultData.effective_patterns) {
|
||
sharedMemory.effective_test_patterns = [
|
||
...new Set([...sharedMemory.effective_test_patterns, ...resultData.effective_patterns])
|
||
]
|
||
}
|
||
sharedMemory.coverage_history.push({
|
||
layer: testDir,
|
||
coverage: coverage,
|
||
target: coverageTarget,
|
||
pass_rate: passRate,
|
||
timestamp: new Date().toISOString()
|
||
})
|
||
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
|
||
|
||
const msgType = resultData.passed ? "tests_passed" : "tests_failed"
|
||
mcp__ccw-tools__team_msg({
|
||
operation: "log", team: teamName, from: "executor", to: "coordinator",
|
||
type: msgType,
|
||
summary: `[executor] ${msgType}: pass=${(passRate*100).toFixed(1)}%, coverage=${coverage}% (target: ${coverageTarget}%), iterations=${iteration}`,
|
||
ref: `${sessionFolder}/results/run-${runNum}.json`
|
||
})
|
||
|
||
SendMessage({
|
||
type: "message", recipient: "coordinator",
|
||
content: `## [executor] Test Execution Results
|
||
|
||
**Task**: ${task.subject}
|
||
**Pass Rate**: ${(passRate * 100).toFixed(1)}%
|
||
**Coverage**: ${coverage}% (target: ${coverageTarget}%)
|
||
**Fix Iterations**: ${iteration}/${MAX_FIX_ITERATIONS}
|
||
**Status**: ${resultData.passed ? '✅ PASSED' : '❌ NEEDS REVISION'}
|
||
|
||
${resultData.defect_patterns ? `### Defect Patterns\n${resultData.defect_patterns.map(p => `- ${p}`).join('\n')}` : ''}`,
|
||
summary: `[executor] ${resultData.passed ? 'PASSED' : 'FAILED'}: ${coverage}% coverage`
|
||
})
|
||
|
||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||
```
|
||
|
||
## Error Handling
|
||
|
||
| Scenario | Resolution |
|
||
|----------|------------|
|
||
| No TESTRUN-* tasks | Idle |
|
||
| Test command fails to start | Check framework installation, notify coordinator |
|
||
| Coverage tool unavailable | Report pass rate only |
|
||
| All tests timeout | Increase timeout, retry once |
|
||
| Auto-fix makes tests worse | Revert, report original failures |
|