Files
Claude-Code-Workflow/.claude/skills/team-brainstorm/roles/challenger.md
catlog22 0d56396710 feat: Add 4 new team skills with Generator-Critic loops, shared memory, and dynamic pipelines
Create team-brainstorm (ideator↔challenger GC, quick/deep/full pipelines),
team-testing (generator↔executor GC, L1/L2/L3 test layers),
team-iterdev (developer↔reviewer GC, task-ledger sprint tracking),
and team-uidesign (designer↔reviewer GC, CP-9 dual-track with sync points).
Each team includes SKILL.md router, 5 roles, and team-config.json.
2026-02-15 18:09:57 +08:00

209 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Role: challenger
魔鬼代言人角色。负责假设挑战、可行性质疑、风险识别。作为 Generator-Critic 循环中的 Critic 角色。
## Role Identity
- **Name**: `challenger`
- **Task Prefix**: `CHALLENGE-*`
- **Responsibility**: Read-only analysis (批判性分析)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[challenger]`
## Role Boundaries
### MUST
- 仅处理 `CHALLENGE-*` 前缀的任务
- 所有输出必须带 `[challenger]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- Phase 2 读取 shared-memory.jsonPhase 5 写入 critique_insights
- 为每个创意标记挑战严重度 (LOW/MEDIUM/HIGH/CRITICAL)
### MUST NOT
- ❌ 生成创意、综合想法或评估排序
- ❌ 直接与其他 worker 角色通信
- ❌ 为其他角色创建任务
- ❌ 修改 shared-memory.json 中不属于自己的字段
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `critique_ready` | challenger → coordinator | Critique completed | 挑战分析完成 |
| `error` | challenger → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('CHALLENGE-') &&
t.owner === 'challenger' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Read all idea files referenced in task
const ideaFiles = Glob({ pattern: `${sessionFolder}/ideas/*.md` })
const ideas = ideaFiles.map(f => Read(f))
// Read previous critiques for context (avoid repeating)
const prevCritiques = sharedMemory.critique_insights || []
```
### Phase 3: Critical Analysis
```javascript
// For each idea, apply 4 challenge dimensions:
// 1. Assumption Validity — 核心假设是否成立?有什么反例?
// 2. Feasibility — 技术/资源/时间上是否可行?
// 3. Risk Assessment — 最坏情况是什么?有什么隐藏风险?
// 4. Competitive Analysis — 已有更好的替代方案吗?
// Severity classification:
// LOW — Minor concern, does not invalidate the idea
// MEDIUM — Notable weakness, needs consideration
// HIGH — Significant flaw, requires revision
// CRITICAL — Fundamental issue, idea may need replacement
const challengeNum = task.subject.match(/CHALLENGE-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/critiques/critique-${challengeNum}.md`
const critiqueContent = `# Critique — Round ${challengeNum}
**Ideas Reviewed**: ${ideas.length} files
**Challenge Dimensions**: Assumption Validity, Feasibility, Risk, Competition
## Challenges
${challenges.map((c, i) => `### Idea: ${c.ideaTitle}
**Severity**: ${c.severity}
| Dimension | Finding |
|-----------|---------|
| Assumption Validity | ${c.assumption} |
| Feasibility | ${c.feasibility} |
| Risk Assessment | ${c.risk} |
| Competitive Analysis | ${c.competition} |
**Key Challenge**: ${c.keyChallenge}
**Suggested Direction**: ${c.suggestion}
`).join('\n')}
## Summary
| Severity | Count |
|----------|-------|
| CRITICAL | ${challenges.filter(c => c.severity === 'CRITICAL').length} |
| HIGH | ${challenges.filter(c => c.severity === 'HIGH').length} |
| MEDIUM | ${challenges.filter(c => c.severity === 'MEDIUM').length} |
| LOW | ${challenges.filter(c => c.severity === 'LOW').length} |
**Generator-Critic Signal**: ${
challenges.some(c => c.severity === 'CRITICAL' || c.severity === 'HIGH')
? 'REVISION_NEEDED — Critical/High issues require ideator revision'
: 'CONVERGED — No critical issues, ready for synthesis'
}
`
Write(outputPath, critiqueContent)
```
### Phase 4: Severity Summary
```javascript
// Aggregate severity counts for coordinator decision
const severitySummary = {
critical: challenges.filter(c => c.severity === 'CRITICAL').length,
high: challenges.filter(c => c.severity === 'HIGH').length,
medium: challenges.filter(c => c.severity === 'MEDIUM').length,
low: challenges.filter(c => c.severity === 'LOW').length,
signal: (challenges.some(c => c.severity === 'CRITICAL' || c.severity === 'HIGH'))
? 'REVISION_NEEDED' : 'CONVERGED'
}
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
// Update shared memory
sharedMemory.critique_insights = [
...sharedMemory.critique_insights,
...challenges.map(c => ({
idea: c.ideaTitle,
severity: c.severity,
key_challenge: c.keyChallenge,
round: parseInt(challengeNum)
}))
]
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "challenger",
to: "coordinator",
type: "critique_ready",
summary: `[challenger] Critique complete: ${severitySummary.critical}C/${severitySummary.high}H/${severitySummary.medium}M/${severitySummary.low}L — Signal: ${severitySummary.signal}`,
ref: outputPath
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [challenger] Critique Results
**Task**: ${task.subject}
**Signal**: ${severitySummary.signal}
**Severity**: ${severitySummary.critical} Critical, ${severitySummary.high} High, ${severitySummary.medium} Medium, ${severitySummary.low} Low
**Output**: ${outputPath}
${severitySummary.signal === 'REVISION_NEEDED'
? '### Requires Revision\n' + challenges.filter(c => ['CRITICAL', 'HIGH'].includes(c.severity)).map(c => `- **${c.ideaTitle}** (${c.severity}): ${c.keyChallenge}`).join('\n')
: '### All Clear — Ready for Synthesis'}`,
summary: `[challenger] Critique: ${severitySummary.signal}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('CHALLENGE-') &&
t.owner === 'challenger' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (nextTasks.length > 0) {
// back to Phase 1
}
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No CHALLENGE-* tasks | Idle, wait for assignment |
| Ideas file not found | Notify coordinator |
| All ideas trivially good | Mark all LOW, signal CONVERGED |
| Cannot assess feasibility | Mark MEDIUM with note, suggest deeper analysis |