Refactor code structure for improved readability and maintainability

This commit is contained in:
catlog22
2026-02-16 13:09:47 +08:00
parent 111b0f6809
commit 02250bd4dc
22 changed files with 6330 additions and 216 deletions

View File

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