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

@@ -6,21 +6,27 @@ allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), Task
# Team Quality Assurance
质量保障团队技能。融合"问题发现"和"软件测试"两大能力域,形成"发现→策略→测试→分析"闭环。通过 Scout 多视角扫描、Generator-Executor 循环、共享缺陷模式数据库,实现渐进式质量保障。所有成员通过 `--role=xxx` 路由到角色执行逻辑。
Unified team skill: quality assurance combining issue discovery and software testing into a closed loop of scout -> strategy -> generate -> execute -> analyze. Uses multi-perspective scanning, Generator-Executor pipeline, and shared defect pattern database for progressive quality assurance. All team members invoke with `--role=xxx` to route to role-specific execution.
## Architecture Overview
## Architecture
```
┌──────────────────────────────────────────────────────────┐
│ Skill(skill="team-quality-assurance", args="--role=xxx")
└────────────────────────┬─────────────────────────────────┘
│ Role Router
┌────────┬───────────┼───────────┬──────────┬──────────┐
↓ ↓ ↓ ↓ ↓ ↓
│ Skill(skill="team-quality-assurance")
│ args="<task-description>" or args="--role=xxx" │
└────────────────────────────┬─────────────────────────────┘
│ Role Router
┌──── --role present? ────┐
│ NO │ YES
↓ ↓
Orchestration Mode Role Dispatch
(auto -> coordinator) (route to role.md)
┌─────┬──────┴──────┬───────────┬──────────┬──────────┐
↓ ↓ ↓ ↓ ↓ ↓
┌────────┐┌───────┐┌──────────┐┌─────────┐┌────────┐┌────────┐
│coordi- ││scout ││strategist││generator││executor││analyst │
nator ││SCOUT-*││QASTRAT-* ││QAGEN-* ││QARUN-* ││QAANA-* │
│ roles/ ││ roles/││ roles/ ││ roles/ ││ roles/ ││ roles/ │
coord ││scout ││strategist││generator││executor││analyst │
││SCOUT-*││QASTRAT-* ││QAGEN-* ││QARUN-* ││QAANA-* │
└────────┘└───────┘└──────────┘└─────────┘└────────┘└────────┘
```
@@ -29,162 +35,182 @@ allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), Task
```
roles/
├── coordinator/
│ ├── role.md # Pipeline 编排(模式选择、任务分发、监控)
│ ├── role.md # Pipeline orchestration (mode selection, task dispatch, monitoring)
│ └── commands/
│ ├── dispatch.md # 任务链创建
│ └── monitor.md # 进度监控
│ ├── dispatch.md # Task chain creation
│ └── monitor.md # Progress monitoring
├── scout/
│ ├── role.md # 多视角问题扫描
│ ├── role.md # Multi-perspective issue scanning
│ └── commands/
│ └── scan.md # 多视角 CLI Fan-out 扫描
│ └── scan.md # Multi-perspective CLI fan-out scanning
├── strategist/
│ ├── role.md # 测试策略制定
│ ├── role.md # Test strategy formulation
│ └── commands/
│ └── analyze-scope.md # 变更范围分析
│ └── analyze-scope.md # Change scope analysis
├── generator/
│ ├── role.md # 测试用例生成
│ ├── role.md # Test case generation
│ └── commands/
│ └── generate-tests.md # 按层级生成测试代码
│ └── generate-tests.md # Layer-based test code generation
├── executor/
│ ├── role.md # 测试执行与修复
│ ├── role.md # Test execution and fix cycles
│ └── commands/
│ └── run-fix-cycle.md # 迭代测试修复循环
│ └── run-fix-cycle.md # Iterative test-fix loop
└── analyst/
├── role.md # 质量分析报告
├── role.md # Quality analysis reporting
└── commands/
└── quality-report.md # 缺陷模式 + 覆盖率分析
└── quality-report.md # Defect pattern + coverage analysis
```
**设计原则**: role.md 保留 Phase 1Task Discovery)和 Phase 5Report内联。Phase 2-4 根据复杂度决定内联或委派到 `commands/*.md`
**Design principle**: role.md retains Phase 1 (Task Discovery) and Phase 5 (Report) inline. Phase 2-4 delegate to `commands/*.md` based on complexity.
## Role Router
### Input Parsing
Parse `$ARGUMENTS` to extract `--role`:
Parse `$ARGUMENTS` to extract `--role`. If absent -> Orchestration Mode (auto route to coordinator).
```javascript
const args = "$ARGUMENTS"
const roleMatch = args.match(/--role[=\s]+(\w+)/)
### Role Registry
if (!roleMatch) {
throw new Error("Missing --role argument. Available roles: coordinator, scout, strategist, generator, executor, analyst")
}
| Role | File | Task Prefix | Type | Compact |
|------|------|-------------|------|---------|
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | (none) | orchestrator | **compressed -> must re-read** |
| scout | [roles/scout/role.md](roles/scout/role.md) | SCOUT-* | pipeline | compressed -> must re-read |
| strategist | [roles/strategist/role.md](roles/strategist/role.md) | QASTRAT-* | pipeline | compressed -> must re-read |
| generator | [roles/generator/role.md](roles/generator/role.md) | QAGEN-* | pipeline | compressed -> must re-read |
| executor | [roles/executor/role.md](roles/executor/role.md) | QARUN-* | pipeline | compressed -> must re-read |
| analyst | [roles/analyst/role.md](roles/analyst/role.md) | QAANA-* | pipeline | compressed -> must re-read |
const role = roleMatch[1]
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "quality-assurance"
> **COMPACT PROTECTION**: Role files are execution documents, not reference material. When context compression occurs and role instructions are reduced to summaries, **you MUST immediately `Read` the corresponding role.md to reload before continuing execution**. Do not execute any Phase based on summaries.
### Dispatch
1. Extract `--role` from arguments
2. If no `--role` -> route to coordinator (Orchestration Mode)
3. Look up role in registry -> Read the role file -> Execute its phases
### Orchestration Mode
When invoked without `--role`, coordinator auto-starts. User just provides task description.
**Invocation**: `Skill(skill="team-quality-assurance", args="<task-description>")`
**Lifecycle**:
```
User provides task description
-> coordinator Phase 1-3: Mode detection + requirement clarification -> TeamCreate -> Create task chain
-> coordinator Phase 4: spawn first batch workers (background) -> STOP
-> Worker executes -> SendMessage callback -> coordinator advances next step
-> Loop until pipeline complete -> Phase 5 report
```
### Role Dispatch
**User Commands** (wake paused coordinator):
```javascript
const VALID_ROLES = {
"coordinator": { file: "roles/coordinator/role.md", prefix: null },
"scout": { file: "roles/scout/role.md", prefix: "SCOUT" },
"strategist": { file: "roles/strategist/role.md", prefix: "QASTRAT" },
"generator": { file: "roles/generator/role.md", prefix: "QAGEN" },
"executor": { file: "roles/executor/role.md", prefix: "QARUN" },
"analyst": { file: "roles/analyst/role.md", prefix: "QAANA" }
}
| Command | Action |
|---------|--------|
| `check` / `status` | Output execution status graph, no advancement |
| `resume` / `continue` | Check worker states, advance next step |
if (!VALID_ROLES[role]) {
throw new Error(`Unknown role: ${role}. Available: ${Object.keys(VALID_ROLES).join(', ')}`)
}
// Read and execute role-specific logic
Read(VALID_ROLES[role].file)
// → Execute the 5-phase process defined in that file
```
### Available Roles
| Role | Task Prefix | Responsibility | Role File |
|------|-------------|----------------|-----------|
| `coordinator` | N/A | QA pipeline 编排、模式选择、质量门控 | [roles/coordinator/role.md](roles/coordinator/role.md) |
| `scout` | SCOUT-* | 多视角问题扫描、主动发现潜在缺陷 | [roles/scout/role.md](roles/scout/role.md) |
| `strategist` | QASTRAT-* | 变更范围分析、测试层级选择、覆盖率目标 | [roles/strategist/role.md](roles/strategist/role.md) |
| `generator` | QAGEN-* | 按层级生成测试用例unit/integration/E2E | [roles/generator/role.md](roles/generator/role.md) |
| `executor` | QARUN-* | 执行测试、收集覆盖率、自动修复循环 | [roles/executor/role.md](roles/executor/role.md) |
| `analyst` | QAANA-* | 缺陷模式分析、覆盖率差距、质量报告 | [roles/analyst/role.md](roles/analyst/role.md) |
---
## Shared Infrastructure
### Role Isolation Rules
The following templates apply to all worker roles. Each role.md only needs to write **Phase 2-4** role-specific logic.
**核心原则**: 每个角色仅能执行自己职责范围内的工作。
### Worker Phase 1: Task Discovery (shared by all workers)
#### Output Tagging强制
Every worker executes the same task discovery flow on startup:
所有角色的输出必须带 `[role_name]` 标识前缀:
1. Call `TaskList()` to get all tasks
2. Filter: subject matches this role's prefix + owner is this role + status is pending + blockedBy is empty
3. No tasks -> idle wait
4. Has tasks -> `TaskGet` for details -> `TaskUpdate` mark in_progress
```javascript
SendMessage({ content: `## [${role}] ...`, summary: `[${role}] ...` })
mcp__ccw-tools__team_msg({ summary: `[${role}] ...` })
**Resume Artifact Check** (prevent duplicate output after resume):
- Check whether this task's output artifact already exists
- Artifact complete -> skip to Phase 5 report completion
- Artifact incomplete or missing -> normal Phase 2-4 execution
### Worker Phase 5: Report (shared by all workers)
Standard reporting flow after task completion:
1. **Message Bus**: Call `mcp__ccw-tools__team_msg` to log message
- Parameters: operation="log", team="quality-assurance", from=<role>, to="coordinator", type=<message-type>, summary="[<role>] <summary>", ref=<artifact-path>
- **CLI fallback**: When MCP unavailable -> `ccw team log --team quality-assurance --from <role> --to coordinator --type <type> --summary "[<role>] ..." --json`
2. **SendMessage**: Send result to coordinator (content and summary both prefixed with `[<role>]`)
3. **TaskUpdate**: Mark task completed
4. **Loop**: Return to Phase 1 to check next task
### Wisdom Accumulation (all roles)
Cross-task knowledge accumulation. Coordinator creates `wisdom/` directory at session initialization.
**Directory**:
```
<session-folder>/wisdom/
├── learnings.md # Patterns and insights
├── decisions.md # Architecture and design decisions
├── conventions.md # Codebase conventions
└── issues.md # Known risks and issues
```
#### Coordinator 隔离
**Worker Load** (Phase 2): Extract `Session: <path>` from task description, read wisdom directory files.
**Worker Contribute** (Phase 4/5): Write this task's discoveries to corresponding wisdom files.
| 允许 | 禁止 |
|------|------|
| 需求澄清 (AskUserQuestion) | ❌ 直接编写测试 |
| 创建任务链 (TaskCreate) | ❌ 直接执行测试或扫描 |
| 模式选择 + 质量门控 | ❌ 直接分析覆盖率 |
| 监控进度 (消息总线) | ❌ 绕过 worker 自行完成 |
### Role Isolation Rules
#### Worker 隔离
#### Output Tagging
| 允许 | 禁止 |
|------|------|
| 处理自己前缀的任务 | ❌ 处理其他角色前缀的任务 |
| 读写 shared-memory.json (自己的字段) | ❌ 为其他角色创建任务 |
| SendMessage 给 coordinator | ❌ 直接与其他 worker 通信 |
All outputs must carry `[role_name]` prefix.
#### Coordinator Isolation
| Allowed | Forbidden |
|---------|-----------|
| Requirement clarification (AskUserQuestion) | Direct test writing |
| Create task chain (TaskCreate) | Direct test execution or scanning |
| Mode selection + quality gating | Direct coverage analysis |
| Monitor progress (message bus) | Bypassing workers |
#### Worker Isolation
| Allowed | Forbidden |
|---------|-----------|
| Process tasks with own prefix | Process tasks with other role prefixes |
| Read/write shared-memory.json (own fields) | Create tasks for other roles |
| SendMessage to coordinator | Communicate directly with other workers |
| Delegate to commands/ files | Modify resources outside own responsibility |
### Team Configuration
```javascript
const TEAM_CONFIG = {
name: "quality-assurance",
sessionDir: ".workflow/.team/QA-{slug}-{date}/",
sharedMemory: "shared-memory.json",
testLayers: {
L1: { name: "Unit Tests", coverage_target: 80 },
L2: { name: "Integration Tests", coverage_target: 60 },
L3: { name: "E2E Tests", coverage_target: 40 }
},
scanPerspectives: ["bug", "security", "ux", "test-coverage", "code-quality"]
}
```
| Setting | Value |
|---------|-------|
| Team name | quality-assurance |
| Session directory | `.workflow/.team/QA-<slug>-<date>/` |
| Test layers | L1: Unit (80%), L2: Integration (60%), L3: E2E (40%) |
| Scan perspectives | bug, security, ux, test-coverage, code-quality |
### Shared Memory(核心创新)
### Shared Memory
```javascript
// 各角色读取共享记忆
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
Cross-role accumulated knowledge stored in `shared-memory.json`:
// 各角色写入自己负责的字段:
// scout → sharedMemory.discovered_issues
// strategist → sharedMemory.test_strategy
// generator → sharedMemory.generated_tests
// executor → sharedMemory.execution_results
// analyst → sharedMemory.defect_patterns + quality_score + coverage_history
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
```
| Field | Owner | Content |
|-------|-------|---------|
| `discovered_issues` | scout | Multi-perspective scan findings |
| `test_strategy` | strategist | Layer selection, coverage targets, scope |
| `generated_tests` | generator | Test file paths and metadata |
| `execution_results` | executor | Test run results and coverage data |
| `defect_patterns` | analyst | Recurring defect pattern database |
| `quality_score` | analyst | Overall quality assessment |
| `coverage_history` | analyst | Coverage trend over time |
Each role reads in Phase 2, writes own fields in Phase 5.
### Message Bus (All Roles)
```javascript
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: role,
to: "coordinator",
type: "<type>",
summary: `[${role}] <summary>`,
ref: "<file_path>"
})
```
Every SendMessage **before**, must call `mcp__ccw-tools__team_msg` to log.
**Message types by role**:
| Role | Types |
|------|-------|
@@ -195,73 +221,222 @@ mcp__ccw-tools__team_msg({
| executor | `tests_passed`, `tests_failed`, `coverage_report`, `error` |
| analyst | `analysis_ready`, `quality_report`, `error` |
### CLI 回退
```javascript
Bash(`ccw team log --team "${teamName}" --from "${role}" --to "coordinator" --type "<type>" --summary "<摘要>" --json`)
```
### Task Lifecycle (All Worker Roles)
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith(`${VALID_ROLES[role].prefix}-`) &&
t.owner === role &&
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-4: Role-specific
// Phase 5: Report + Loop
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: role, to: "coordinator", type: "...", summary: `[${role}] ...` })
SendMessage({ type: "message", recipient: "coordinator", content: `## [${role}] ...`, summary: `[${role}] ...` })
TaskUpdate({ taskId: task.id, status: 'completed' })
```
---
## Three-Mode Pipeline Architecture
```
Discovery Mode (问题发现优先):
SCOUT-001(多视角扫描) → QASTRAT-001 → QAGEN-001 → QARUN-001 → QAANA-001
Testing Mode (测试优先,跳过 scout):
QASTRAT-001(变更分析) → QAGEN-001(L1) → QARUN-001(L1) → QAGEN-002(L2) → QARUN-002(L2) → QAANA-001
Full QA Mode (完整闭环):
SCOUT-001(扫描) → QASTRAT-001(策略) → [QAGEN-001(L1) + QAGEN-002(L2)](parallel) → [QARUN-001 + QARUN-002](parallel) → QAANA-001(分析) → SCOUT-002(回归扫描)
```
### Mode Auto-Detection
```javascript
function detectQAMode(args, taskDescription) {
if (/--mode[=\s]+(discovery|testing|full)/.test(args)) {
return args.match(/--mode[=\s]+(\w+)/)[1]
}
// 自动检测
if (/发现|扫描|scan|discover|issue|问题/.test(taskDescription)) return 'discovery'
if (/测试|test|覆盖|coverage|TDD/.test(taskDescription)) return 'testing'
return 'full'
}
```
| 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) |
### Generator-Executor Loop (GC 循环)
### Pipeline Diagrams
```
QAGEN → QARUN → (if coverage < target) → QAGEN-fix → QARUN-2
(if coverage >= target) → next layer or QAANA
Discovery Mode (issue discovery first):
SCOUT-001(multi-perspective scan) -> QASTRAT-001 -> QAGEN-001 -> QARUN-001 -> QAANA-001
Testing Mode (skip scout, test first):
QASTRAT-001(change analysis) -> QAGEN-001(L1) -> QARUN-001(L1) -> QAGEN-002(L2) -> QARUN-002(L2) -> QAANA-001
Full QA Mode (complete closed loop):
SCOUT-001(scan) -> QASTRAT-001(strategy)
-> [QAGEN-001(L1) || QAGEN-002(L2)](parallel) -> [QARUN-001 || QARUN-002](parallel)
-> QAANA-001(analysis) -> SCOUT-002(regression scan)
```
### Generator-Executor Pipeline (GC Loop)
Generator and executor iterate per test layer until coverage targets are met:
```
QAGEN -> QARUN -> (if coverage < target) -> QAGEN-fix -> QARUN-2
(if coverage >= target) -> next layer or QAANA
```
Coordinator monitors GC loop progress. After 3 GC iterations without convergence, accept current coverage with warning.
In Full QA mode, spawn N generator agents in parallel (one per test layer). Each receives a QAGEN-N task with layer assignment. Use `run_in_background: true` for all spawns, then coordinator stops and waits for callbacks. Similarly spawn N executor agents in parallel for QARUN-N tasks.
### Cadence Control
**Beat model**: Event-driven, each beat = coordinator wake -> process -> spawn -> STOP.
```
Beat Cycle (single beat)
═══════════════════════════════════════════════════════════
Event Coordinator Workers
───────────────────────────────────────────────────────────
callback/resume ──> ┌─ handleCallback ─┐
│ mark completed │
│ check pipeline │
├─ handleSpawnNext ─┤
│ find ready tasks │
│ spawn workers ───┼──> [Worker A] Phase 1-5
│ (parallel OK) ──┼──> [Worker B] Phase 1-5
└─ STOP (idle) ─────┘ │
callback <─────────────────────────────────────────┘
(next beat) SendMessage + TaskUpdate(completed)
═══════════════════════════════════════════════════════════
```
**Pipeline beat view**:
```
Discovery mode (5 beats, strictly serial)
──────────────────────────────────────────────────────────
Beat 1 2 3 4 5
│ │ │ │ │
SCOUT -> STRAT -> GEN -> RUN -> ANA
▲ ▲
pipeline pipeline
start done
S=SCOUT STRAT=QASTRAT GEN=QAGEN RUN=QARUN ANA=QAANA
Testing mode (6 beats, layer progression)
──────────────────────────────────────────────────────────
Beat 1 2 3 4 5 6
│ │ │ │ │ │
STRAT -> GEN-L1 -> RUN-L1 -> GEN-L2 -> RUN-L2 -> ANA
▲ ▲
no scout analysis
(test only)
Full QA mode (6 beats, with parallel windows + regression)
──────────────────────────────────────────────────────────
Beat 1 2 3 4 5 6
│ │ ┌────┴────┐ ┌────┴────┐ │ │
SCOUT -> STRAT -> GEN-L1||GEN-L2 -> RUN-1||RUN-2 -> ANA -> SCOUT-2
▲ ▲
parallel gen regression
scan
```
**Checkpoints**:
| Trigger | Location | Behavior |
|---------|----------|----------|
| GC loop limit | QARUN coverage < target | After 3 iterations, accept current coverage with warning |
| Pipeline stall | No ready + no running | Check missing tasks, report to user |
| Regression scan (full mode) | QAANA-001 complete | Trigger SCOUT-002 for regression verification |
**Stall Detection** (coordinator `handleCheck` executes):
| Check | Condition | Resolution |
|-------|-----------|------------|
| Worker no response | in_progress task no callback | Report waiting task list, suggest user `resume` |
| Pipeline deadlock | no ready + no running + has pending | Check blockedBy dependency chain, report blocking point |
| GC loop exceeded | generator/executor iteration > 3 | Terminate loop, output latest coverage report |
### Task Metadata Registry
| Task ID | Role | Phase | Dependencies | Description |
|---------|------|-------|-------------|-------------|
| SCOUT-001 | scout | discovery | (none) | Multi-perspective issue scanning |
| QASTRAT-001 | strategist | strategy | SCOUT-001 or (none) | Change scope analysis + test strategy |
| QAGEN-001 | generator | generation | QASTRAT-001 | L1 unit test generation |
| QAGEN-002 | generator | generation | QASTRAT-001 (full mode) | L2 integration test generation |
| QARUN-001 | executor | execution | QAGEN-001 | L1 test execution + fix cycles |
| QARUN-002 | executor | execution | QAGEN-002 (full mode) | L2 test execution + fix cycles |
| QAANA-001 | analyst | analysis | QARUN-001 (+ QARUN-002) | Defect pattern analysis + quality report |
| SCOUT-002 | scout | regression | QAANA-001 (full mode) | Regression scan after fixes |
---
## Coordinator Spawn Template
When coordinator spawns workers, use background mode (Spawn-and-Stop):
```
Task({
subagent_type: "general-purpose",
description: "Spawn <role> worker",
team_name: <team-name>,
name: "<role>",
run_in_background: true,
prompt: `You are team "<team-name>" <ROLE>.
## Primary Directive
All your work must be executed through Skill to load role definition:
Skill(skill="team-quality-assurance", args="--role=<role>")
Current requirement: <task-description>
Session: <session-folder>
## Role Guidelines
- Only process <PREFIX>-* tasks, do not execute other role work
- All output prefixed with [<role>] identifier
- Only communicate with coordinator
- Do not use TaskCreate for other roles
- Call mcp__ccw-tools__team_msg before every SendMessage
## Workflow
1. Call Skill -> load role definition and execution logic
2. Follow role.md 5-Phase flow
3. team_msg + SendMessage results to coordinator
4. TaskUpdate completed -> check next task`
})
```
### Parallel Spawn (N agents for same role)
> When pipeline has parallel tasks assigned to the same role, spawn N distinct agents with unique names. A single agent can only process tasks serially.
**Parallel detection**:
| Condition | Action |
|-----------|--------|
| N parallel tasks for same role prefix | Spawn N agents named `<role>-1`, `<role>-2` ... |
| Single task for role | Standard spawn (single agent) |
**Parallel spawn template**:
```
Task({
subagent_type: "general-purpose",
description: "Spawn <role>-<N> worker",
team_name: <team-name>,
name: "<role>-<N>",
run_in_background: true,
prompt: `You are team "<team-name>" <ROLE> (<role>-<N>).
Your agent name is "<role>-<N>", use this name for task discovery owner matching.
## Primary Directive
Skill(skill="team-quality-assurance", args="--role=<role> --agent-name=<role>-<N>")
## Role Guidelines
- Only process tasks where owner === "<role>-<N>" with <PREFIX>-* prefix
- All output prefixed with [<role>] identifier
## Workflow
1. TaskList -> find tasks where owner === "<role>-<N>" with <PREFIX>-* prefix
2. Skill -> execute role definition
3. team_msg + SendMessage results to coordinator
4. TaskUpdate completed -> check next task`
})
```
**Dispatch must match agent names**: In dispatch, parallel tasks use instance-specific owner: `<role>-<N>`. In role.md, task discovery uses --agent-name for owner matching.
## Unified Session Directory
```
.workflow/.team/QA-{slug}-{YYYY-MM-DD}/
├── team-session.json
├── shared-memory.json # 发现的问题 / 测试策略 / 缺陷模式 / 覆盖率历史
.workflow/.team/QA-<slug>-<YYYY-MM-DD>/
├── team-session.json # Session state
├── shared-memory.json # Discovered issues / test strategy / defect patterns / coverage history
├── wisdom/ # Cross-task knowledge
│ ├── learnings.md
│ ├── decisions.md
│ ├── conventions.md
│ └── issues.md
├── scan/ # Scout output
│ └── scan-results.json
├── strategy/ # Strategist output
@@ -277,218 +452,13 @@ QAGEN → QARUN → (if coverage < target) → QAGEN-fix → QARUN-2
└── quality-report.md
```
## Coordinator Spawn Template
```javascript
TeamCreate({ team_name: teamName })
// Scout
Task({
subagent_type: "general-purpose",
description: `Spawn scout worker`,
team_name: teamName,
name: "scout",
prompt: `你是 team "${teamName}" 的 SCOUT。
当你收到 SCOUT-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=scout") 执行。
当前需求: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 SCOUT-* 前缀的任务,不得执行其他角色的工作
- 所有输出SendMessage、team_msg必须带 [scout] 标识前缀
- 仅与 coordinator 通信,不得直接联系其他 worker
- 不得使用 TaskCreate 为其他角色创建任务
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 SCOUT-* 任务
2. Skill(skill="team-quality-assurance", args="--role=scout") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [scout] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
// Strategist
Task({
subagent_type: "general-purpose",
description: `Spawn strategist worker`,
team_name: teamName,
name: "strategist",
prompt: `你是 team "${teamName}" 的 STRATEGIST。
当你收到 QASTRAT-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=strategist") 执行。
当前需求: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 QASTRAT-* 前缀的任务
- 所有输出必须带 [strategist] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 QASTRAT-* 任务
2. Skill(skill="team-quality-assurance", args="--role=strategist") 执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate completed → 检查下一个任务`
})
// Generator — parallel instances for full mode (generator-1, generator-2)
const isFullMode = qaMode === 'full'
if (isFullMode) {
for (let i = 1; i <= 2; i++) {
const agentName = `generator-${i}`
Task({
subagent_type: "general-purpose",
description: `Spawn ${agentName} worker`,
team_name: teamName,
name: agentName,
prompt: `你是 team "${teamName}" 的 GENERATOR (${agentName})。
你的 agent 名称是 "${agentName}",任务发现时用此名称匹配 owner。
当你收到 QAGEN-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=generator --agent-name=${agentName}") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 owner 为 "${agentName}" 的 QAGEN-* 前缀任务
- 所有输出必须带 [generator] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 owner === "${agentName}" 的 QAGEN-* 任务
2. Skill(skill="team-quality-assurance", args="--role=generator --agent-name=${agentName}") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
}
} else {
Task({
subagent_type: "general-purpose",
description: `Spawn generator worker`,
team_name: teamName,
name: "generator",
prompt: `你是 team "${teamName}" 的 GENERATOR。
当你收到 QAGEN-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=generator") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 QAGEN-* 前缀的任务
- 所有输出必须带 [generator] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 QAGEN-* 任务
2. Skill(skill="team-quality-assurance", args="--role=generator") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
}
// Executor — parallel instances for full mode (executor-1, executor-2)
if (isFullMode) {
for (let i = 1; i <= 2; i++) {
const agentName = `executor-${i}`
Task({
subagent_type: "general-purpose",
description: `Spawn ${agentName} worker`,
team_name: teamName,
name: agentName,
prompt: `你是 team "${teamName}" 的 EXECUTOR (${agentName})。
你的 agent 名称是 "${agentName}",任务发现时用此名称匹配 owner。
当你收到 QARUN-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=executor --agent-name=${agentName}") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 owner 为 "${agentName}" 的 QARUN-* 前缀任务
- 所有输出必须带 [executor] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 owner === "${agentName}" 的 QARUN-* 任务
2. Skill(skill="team-quality-assurance", args="--role=executor --agent-name=${agentName}") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
}
} else {
Task({
subagent_type: "general-purpose",
description: `Spawn executor worker`,
team_name: teamName,
name: "executor",
prompt: `你是 team "${teamName}" 的 EXECUTOR。
当你收到 QARUN-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=executor") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 QARUN-* 前缀的任务
- 所有输出必须带 [executor] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 QARUN-* 任务
2. Skill(skill="team-quality-assurance", args="--role=executor") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
}
// Analyst
Task({
subagent_type: "general-purpose",
description: `Spawn analyst worker`,
team_name: teamName,
name: "analyst",
prompt: `你是 team "${teamName}" 的 ANALYST。
当你收到 QAANA-* 任务时,调用 Skill(skill="team-quality-assurance", args="--role=analyst") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 QAANA-* 前缀的任务
- 所有输出必须带 [analyst] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 QAANA-* 任务
2. Skill(skill="team-quality-assurance", args="--role=analyst") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown --role value | Error with available role list |
| Missing --role arg | Error with usage hint |
| Role file not found | Error with expected path (roles/{name}/role.md) |
| Missing --role arg | Orchestration Mode -> auto route to coordinator |
| Role file not found | Error with expected path (roles/<name>/role.md) |
| Task prefix conflict | Log warning, proceed |
| Coverage never reaches target | After 3 GC loops, accept current with warning |
| Scout finds no issues | Report clean scan, skip to testing mode |

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