Files
Claude-Code-Workflow/.claude/skills/team-lifecycle/roles/discussant.md
catlog22 75558dc411 feat: add Terminal Dashboard components and state management
- Implemented DashboardToolbar for managing panel toggles and layout presets.
- Created FloatingPanel for a generic sliding panel interface.
- Developed TerminalGrid for rendering a recursive layout of terminal panes.
- Added TerminalPane to encapsulate individual terminal instances with toolbar actions.
- Introduced layout utilities for managing Allotment layout trees.
- Established Zustand store for terminal grid state management, supporting pane operations and layout resets.
2026-02-14 22:13:45 +08:00

11 KiB

Role: discussant

Multi-perspective critique, consensus building, and conflict escalation. The key differentiator of the spec team workflow — ensuring quality feedback between each phase transition.

Role Identity

  • Name: discussant
  • Task Prefix: DISCUSS-*
  • Responsibility: Load Artifact → Multi-Perspective Critique → Synthesize Consensus → Report
  • Communication: SendMessage to coordinator only

Message Types

Type Direction Trigger Description
discussion_ready discussant → coordinator Discussion complete, consensus reached With discussion record path and decision summary
discussion_blocked discussant → coordinator Cannot reach consensus With divergence points and options, needs coordinator
impl_progress discussant → coordinator Long discussion progress Multi-perspective analysis progress
error discussant → coordinator Discussion cannot proceed Input artifact missing, etc.

Message Bus

Before every SendMessage, MUST call mcp__ccw-tools__team_msg to log:

// Discussion complete
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "discussant", to: "coordinator", type: "discussion_ready", summary: "Scope discussion consensus reached: 3 decisions", ref: `${sessionFolder}/discussions/discuss-001-scope.md` })

// Discussion blocked
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "discussant", to: "coordinator", type: "discussion_blocked", summary: "Cannot reach consensus on tech stack", data: { reason: "...", options: [...] } })

// Error report
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "discussant", to: "coordinator", type: "error", summary: "Input artifact missing" })

CLI Fallback

When mcp__ccw-tools__team_msg MCP is unavailable:

Bash(`ccw team log --team "${teamName}" --from "discussant" --to "coordinator" --type "discussion_ready" --summary "Discussion complete" --ref "${sessionFolder}/discussions/discuss-001-scope.md" --json`)

Discussion Dimension Model

Each discussion round analyzes from 4 perspectives:

Perspective Focus Representative
Product Market fit, user value, business viability, competitive differentiation Product Manager
Technical Feasibility, tech debt, performance, security, maintainability Tech Lead
Quality Completeness, testability, consistency, standards compliance QA Lead
Risk Risk identification, dependency analysis, assumption validation, failure modes Risk Analyst
Coverage Requirement completeness vs original intent, scope drift, gap detection Requirements Analyst

Discussion Round Configuration

Round Artifact Key Perspectives Focus
DISCUSS-001 discovery-context product + risk + coverage Scope confirmation, direction, initial coverage check
DISCUSS-002 product-brief product + technical + quality + coverage Positioning, feasibility, requirement coverage
DISCUSS-003 requirements quality + product + coverage Completeness, priority, gap detection
DISCUSS-004 architecture technical + risk Tech choices, security
DISCUSS-005 epics product + technical + quality + coverage MVP scope, estimation, requirement tracing
DISCUSS-006 readiness-report all 5 perspectives Final sign-off

Execution (5-Phase)

Phase 1: Task Discovery

const tasks = TaskList()
const myTasks = tasks.filter(t =>
  t.subject.startsWith('DISCUSS-') &&
  t.owner === 'discussant' &&
  t.status === 'pending' &&
  t.blockedBy.length === 0
)

if (myTasks.length === 0) return // idle

const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })

Phase 2: Artifact Loading

const sessionMatch = task.description.match(/Session:\s*(.+)/)
const sessionFolder = sessionMatch ? sessionMatch[1].trim() : ''
const roundMatch = task.subject.match(/DISCUSS-(\d+)/)
const roundNumber = roundMatch ? parseInt(roundMatch[1]) : 0

const roundConfig = {
  1: { artifact: 'discovery-context.json', type: 'json', outputFile: 'discuss-001-scope.md', perspectives: ['product', 'risk', 'coverage'], label: '范围讨论' },
  2: { artifact: 'product-brief.md', type: 'md', outputFile: 'discuss-002-brief.md', perspectives: ['product', 'technical', 'quality', 'coverage'], label: 'Brief评审' },
  3: { artifact: 'requirements/_index.md', type: 'md', outputFile: 'discuss-003-requirements.md', perspectives: ['quality', 'product', 'coverage'], label: '需求讨论' },
  4: { artifact: 'architecture/_index.md', type: 'md', outputFile: 'discuss-004-architecture.md', perspectives: ['technical', 'risk'], label: '架构讨论' },
  5: { artifact: 'epics/_index.md', type: 'md', outputFile: 'discuss-005-epics.md', perspectives: ['product', 'technical', 'quality', 'coverage'], label: 'Epics讨论' },
  6: { artifact: 'readiness-report.md', type: 'md', outputFile: 'discuss-006-final.md', perspectives: ['product', 'technical', 'quality', 'risk', 'coverage'], label: '最终签收' }
}

const config = roundConfig[roundNumber]
// Load target artifact and prior discussion records for continuity
Bash(`mkdir -p ${sessionFolder}/discussions`)

Phase 3: Multi-Perspective Critique

Launch parallel CLI analyses for each required perspective:

  • Product Perspective (gemini): Market fit, user value, business viability, competitive differentiation. Rate 1-5 with improvement suggestions.
  • Technical Perspective (codex): Feasibility, complexity, architecture decisions, tech debt risks. Rate 1-5.
  • Quality Perspective (claude): Completeness, testability, consistency, ambiguity detection. Rate 1-5.
  • Risk Perspective (gemini): Risk identification, dependency analysis, assumption validation, failure modes. Rate risk level.
  • Coverage Perspective (gemini): Compare current artifact against original requirements in discovery-context.json. Identify covered_requirements[], partial_requirements[], missing_requirements[], scope_creep[]. Rate coverage 1-5. If missing_requirements is non-empty, flag as critical divergence.

Each CLI call produces structured critique with: strengths[], weaknesses[], suggestions[], rating. Coverage perspective additionally outputs: covered_requirements[], missing_requirements[], scope_creep[].

Phase 4: Consensus Synthesis

const synthesis = {
  convergent_themes: [],
  divergent_views: [],
  action_items: [],
  open_questions: [],
  decisions: [],
  risk_flags: [],
  overall_sentiment: '',    // positive/neutral/concerns/critical
  consensus_reached: true   // false if major unresolvable conflicts
}

// Extract convergent themes (items mentioned positively by 2+ perspectives)
// Extract divergent views (items where perspectives conflict)
// Check coverage gaps from coverage perspective (if present)
const coverageResult = perspectiveResults.find(p => p.perspective === 'coverage')
if (coverageResult?.missing_requirements?.length > 0) {
  synthesis.coverage_gaps = coverageResult.missing_requirements
  synthesis.divergent_views.push({
    topic: 'requirement_coverage_gap',
    description: `${coverageResult.missing_requirements.length} requirements from discovery-context not covered: ${coverageResult.missing_requirements.join(', ')}`,
    severity: 'high',
    source: 'coverage'
  })
}
// Check for unresolvable conflicts
const criticalDivergences = synthesis.divergent_views.filter(d => d.severity === 'high')
if (criticalDivergences.length > 0) synthesis.consensus_reached = false

// Determine overall sentiment from average rating
// Generate discussion record markdown with all perspectives, convergence, divergence, action items

Write(`${sessionFolder}/discussions/${config.outputFile}`, discussionRecord)

Phase 5: Report to Coordinator

if (synthesis.consensus_reached) {
  mcp__ccw-tools__team_msg({
    operation: "log", team: teamName,
    from: "discussant", to: "coordinator",
    type: "discussion_ready",
    summary: `${config.label}讨论完成: ${synthesis.action_items.length}个行动项, ${synthesis.open_questions.length}个开放问题, 总体${synthesis.overall_sentiment}`,
    ref: `${sessionFolder}/discussions/${config.outputFile}`
  })

  SendMessage({
    type: "message",
    recipient: "coordinator",
    content: `## 讨论结果: ${config.label}

**Task**: ${task.subject}
**共识**: 已达成
**总体评价**: ${synthesis.overall_sentiment}

### 行动项 (${synthesis.action_items.length})
${synthesis.action_items.map((item, i) => (i+1) + '. ' + item).join('\n') || '无'}

### 开放问题 (${synthesis.open_questions.length})
${synthesis.open_questions.map((q, i) => (i+1) + '. ' + q).join('\n') || '无'}

### 讨论记录
${sessionFolder}/discussions/${config.outputFile}

共识已达成,可推进至下一阶段。`,
    summary: `${config.label}共识达成: ${synthesis.action_items.length}行动项`
  })

  TaskUpdate({ taskId: task.id, status: 'completed' })
} else {
  // Consensus blocked - escalate to coordinator
  mcp__ccw-tools__team_msg({
    operation: "log", team: teamName,
    from: "discussant", to: "coordinator",
    type: "discussion_blocked",
    summary: `${config.label}讨论阻塞: ${criticalDivergences.length}个关键分歧需决策`,
    data: {
      reason: criticalDivergences.map(d => d.description).join('; '),
      options: criticalDivergences.map(d => ({ label: d.topic, description: d.options?.join(' vs ') || d.description }))
    }
  })

  SendMessage({
    type: "message",
    recipient: "coordinator",
    content: `## 讨论阻塞: ${config.label}

**Task**: ${task.subject}
**状态**: 无法达成共识,需要 coordinator 介入

### 关键分歧
${criticalDivergences.map((d, i) => (i+1) + '. **' + d.topic + '**: ' + d.description).join('\n\n')}

请通过 AskUserQuestion 收集用户对分歧点的决策。`,
    summary: `${config.label}阻塞: ${criticalDivergences.length}分歧`
  })
  // Keep task in_progress, wait for coordinator resolution
}

// Check for next DISCUSS task → back to Phase 1

Error Handling

Scenario Resolution
No DISCUSS-* tasks available Idle, wait for coordinator assignment
Target artifact not found Notify coordinator, request prerequisite completion
CLI perspective analysis failure Fallback to direct Claude analysis for that perspective
All CLI analyses fail Generate basic discussion from direct reading
Consensus timeout (all perspectives diverge) Escalate as discussion_blocked
Prior discussion records missing Continue without continuity context
Session folder not found Notify coordinator, request session path
Unexpected error Log error via team_msg, report to coordinator