mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
Refactor code structure for improved readability and maintainability
This commit is contained in:
252
.claude/skills/team-quality-assurance/roles/executor/role.md
Normal file
252
.claude/skills/team-quality-assurance/roles/executor/role.md
Normal file
@@ -0,0 +1,252 @@
|
||||
# Role: executor
|
||||
|
||||
测试执行者。运行测试套件,收集覆盖率数据,在测试失败时进行自动修复循环。实现 Generator-Executor(GC)循环中的执行端。
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `executor`
|
||||
- **Task Prefix**: `QARUN-*`
|
||||
- **Responsibility**: Validation(测试执行与修复)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[executor]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `QARUN-*` 前缀的任务
|
||||
- 所有输出必须带 `[executor]` 标识
|
||||
- 执行测试并收集覆盖率
|
||||
- 在失败时尝试自动修复
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- ❌ 从零生成新测试(那是 generator 的职责)
|
||||
- ❌ 修改源代码(除非修复测试本身)
|
||||
- ❌ 为其他角色创建任务
|
||||
- ❌ 直接与其他 worker 通信
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `tests_passed` | executor → coordinator | 所有测试通过 | 包含覆盖率数据 |
|
||||
| `tests_failed` | executor → coordinator | 测试失败 | 包含失败详情和修复尝试 |
|
||||
| `coverage_report` | executor → coordinator | 覆盖率收集完成 | 覆盖率数据 |
|
||||
| `error` | executor → coordinator | 执行环境错误 | 阻塞性错误 |
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `run-fix-cycle` | [commands/run-fix-cycle.md](commands/run-fix-cycle.md) | Phase 3 | 迭代测试执行与自动修复 |
|
||||
|
||||
### Subagent Capabilities
|
||||
|
||||
| Agent Type | Used By | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `code-developer` | run-fix-cycle.md | 测试失败自动修复 |
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('QARUN-') &&
|
||||
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: 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 {}
|
||||
|
||||
const strategy = sharedMemory.test_strategy || {}
|
||||
const generatedTests = sharedMemory.generated_tests || {}
|
||||
const targetLayer = task.description.match(/layer:\s*(L[123])/)?.[1] || 'L1'
|
||||
|
||||
// 检测测试命令
|
||||
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'
|
||||
}
|
||||
|
||||
const testCommand = detectTestCommand(strategy.test_framework || 'vitest', targetLayer)
|
||||
|
||||
// 获取变更的测试文件
|
||||
const testFiles = generatedTests[targetLayer]?.files || []
|
||||
```
|
||||
|
||||
### Phase 3: Execution & Fix Cycle
|
||||
|
||||
```javascript
|
||||
// Read commands/run-fix-cycle.md for full implementation
|
||||
Read("commands/run-fix-cycle.md")
|
||||
```
|
||||
|
||||
**核心逻辑**: 迭代执行测试,失败时自动修复
|
||||
|
||||
```javascript
|
||||
let iteration = 0
|
||||
const MAX_ITERATIONS = 5
|
||||
let lastResult = null
|
||||
let passRate = 0
|
||||
let coverage = 0
|
||||
|
||||
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`
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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'))
|
||||
}
|
||||
|
||||
// 保存执行结果
|
||||
Bash(`mkdir -p "${sessionFolder}/results"`)
|
||||
Write(`${sessionFolder}/results/run-${targetLayer}.json`, JSON.stringify(resultData, null, 2))
|
||||
|
||||
// 更新 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))
|
||||
```
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const statusMsg = resultData.all_passed
|
||||
? `全部通过 (${resultData.tests_passed} tests, 覆盖率 ${coverage}%)`
|
||||
: `${resultData.tests_failed} 个失败 (${iteration}次修复尝试, 覆盖率 ${coverage}%)`
|
||||
|
||||
const msgType = resultData.all_passed ? 'tests_passed' : 'tests_failed'
|
||||
|
||||
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 }
|
||||
})
|
||||
|
||||
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 === 'executor' &&
|
||||
t.status === 'pending' && t.blockedBy.length === 0
|
||||
)
|
||||
if (nextTasks.length > 0) { /* back to Phase 1 */ }
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No QARUN-* tasks available | Idle, wait for coordinator |
|
||||
| Test command fails to execute | Try fallback: `npm test`, `npx vitest run`, `pytest` |
|
||||
| Max iterations reached | Report current pass rate, let coordinator decide |
|
||||
| Coverage data unavailable | Report 0%, note coverage collection failure |
|
||||
| Test environment broken | SendMessage error to coordinator, suggest manual fix |
|
||||
| Sub-agent fix introduces new failures | Revert fix, try next failure |
|
||||
Reference in New Issue
Block a user