Files
Claude-Code-Workflow/.claude/skills/team-testing/roles/executor.md
catlog22 0d56396710 feat: Add 4 new team skills with Generator-Critic loops, shared memory, and dynamic pipelines
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.
2026-02-15 18:09:57 +08:00

6.6 KiB
Raw Blame History

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.jsonPhase 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

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

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

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

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

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