Files
Claude-Code-Workflow/.claude/skills/team-uidesign/roles/reviewer.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

10 KiB
Raw Blame History

Role: reviewer

Design auditor responsible for consistency, accessibility compliance, and visual quality review. Acts as Critic in the designer↔reviewer Generator-Critic loop. Serves as sync point gatekeeper in dual-track pipelines.

Role Identity

  • Name: reviewer
  • Task Prefix: AUDIT
  • Responsibility Type: Read-only analysis (Validation)
  • Responsibility: Design consistency audit, accessibility compliance, visual review
  • Toolbox: Read, Glob, Grep, Bash(read-only), Task(Explore)

Message Types

Type When Content
audit_passed Score >= 8, no critical issues Audit report + score
audit_result Score 6-7, non-critical issues Feedback for GC revision
fix_required Score < 6, critical issues found Critical issues list
error Failure Error details

Execution

Phase 1: Task Discovery

const tasks = TaskList()
const myTasks = tasks.filter(t =>
  t.subject.startsWith('AUDIT-') &&
  t.owner === 'reviewer' &&
  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' })

// Detect audit type
const isTokenAudit = task.subject.includes('令牌') || task.subject.includes('token')
const isComponentAudit = task.subject.includes('组件') || task.subject.includes('component')
const isFinalAudit = task.subject.includes('最终') || task.subject.includes('final')
const isSyncPoint = task.subject.includes('同步点') || task.subject.includes('Sync')

Phase 2: Context Loading + Shared Memory Read

const sessionFolder = task.description.match(/Session:\s*(.+)/)?.[1]?.trim()

// Read shared memory for audit history
let sharedMemory = {}
try {
  sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
} catch {}

const auditHistory = sharedMemory.audit_history || []
const tokenRegistry = sharedMemory.design_token_registry || {}

// Read design artifacts to audit
let designTokens = null
let componentSpecs = []
try {
  designTokens = JSON.parse(Read(`${sessionFolder}/design/design-tokens.json`))
} catch {}

const specFiles = Glob({ pattern: `${sessionFolder}/design/component-specs/*.md` })
componentSpecs = specFiles.map(f => ({ path: f, content: Read(f) }))

// Read build artifacts if final audit
let buildArtifacts = []
if (isFinalAudit) {
  const buildFiles = Glob({ pattern: `${sessionFolder}/build/**/*` })
  buildArtifacts = buildFiles
}

Phase 3: Core Execution

Audit Dimensions

4 dimensions scored on 1-10 scale:

Dimension Weight Criteria
Consistency 25% Token usage, naming conventions, visual uniformity
Accessibility 30% WCAG AA compliance, ARIA attributes, keyboard nav, contrast
Completeness 25% All states defined, responsive specs, edge cases
Quality 20% Token reference integrity, documentation clarity, maintainability

Token Audit (AUDIT for token systems)

if (isTokenAudit && designTokens) {
  const tokenAudit = {
    consistency: { score: 0, issues: [] },
    accessibility: { score: 0, issues: [] },
    completeness: { score: 0, issues: [] },
    quality: { score: 0, issues: [] }
  }

  // Consistency checks
  // - Naming convention (kebab-case, semantic names)
  // - Value patterns (consistent units: rem/px/%)
  // - Theme completeness (light + dark for all colors)

  // Accessibility checks
  // - Color contrast ratios (text on background >= 4.5:1)
  // - Focus indicator colors visible against backgrounds
  // - Font sizes meet minimum (>= 12px / 0.75rem)

  // Completeness checks
  // - All token categories present (color, typography, spacing, shadow, border)
  // - Breakpoints defined
  // - Semantic color tokens (success, warning, error, info)

  // Quality checks
  // - $type metadata present (W3C format)
  // - Values are valid (CSS-parseable)
  // - No duplicate definitions
}

Component Audit

if (isComponentAudit && componentSpecs.length > 0) {
  componentSpecs.forEach(spec => {
    // Consistency: token references resolve, naming matches convention
    // Accessibility: ARIA roles defined, keyboard behavior specified, focus indicator
    // Completeness: all 5 states (default/hover/focus/active/disabled), responsive breakpoints
    // Quality: clear descriptions, variant system, interaction specs
  })
}

Final Audit (Cross-cutting)

if (isFinalAudit) {
  // Token ↔ Component consistency
  // - All token references in components resolve to defined tokens
  // - No hardcoded values in component specs

  // Code ↔ Design consistency (if build artifacts exist)
  // - CSS variables match design tokens
  // - Component implementation matches spec states
  // - ARIA attributes implemented as specified

  // Cross-component consistency
  // - Consistent spacing patterns
  // - Consistent color usage for similar elements
  // - Consistent interaction patterns
}

Score Calculation

const weights = { consistency: 0.25, accessibility: 0.30, completeness: 0.25, quality: 0.20 }
const overallScore = Math.round(
  tokenAudit.consistency.score * weights.consistency +
  tokenAudit.accessibility.score * weights.accessibility +
  tokenAudit.completeness.score * weights.completeness +
  tokenAudit.quality.score * weights.quality
)

// Severity classification
const criticalIssues = allIssues.filter(i => i.severity === 'CRITICAL')
const highIssues = allIssues.filter(i => i.severity === 'HIGH')
const mediumIssues = allIssues.filter(i => i.severity === 'MEDIUM')

// Determine signal
let signal
if (overallScore >= 8 && criticalIssues.length === 0) {
  signal = 'audit_passed'       // GC CONVERGED
} else if (overallScore >= 6 && criticalIssues.length === 0) {
  signal = 'audit_result'       // GC REVISION NEEDED
} else {
  signal = 'fix_required'       // GC CRITICAL FIX NEEDED
}

Audit Report Generation

const auditNumber = task.subject.match(/AUDIT-(\d+)/)?.[1] || '001'
const auditReport = `# Audit Report: AUDIT-${auditNumber}

## Summary
- **Overall Score**: ${overallScore}/10
- **Signal**: ${signal}
- **Critical Issues**: ${criticalIssues.length}
- **High Issues**: ${highIssues.length}
- **Medium Issues**: ${mediumIssues.length}
${isSyncPoint ? `\n**⚡ Sync Point**: ${signal === 'audit_passed' ? 'PASSED — 双轨任务已解锁' : 'BLOCKED — 需要修订后重新审查'}` : ''}

## Dimension Scores

| Dimension | Score | Weight | Weighted |
|-----------|-------|--------|----------|
| Consistency | ${tokenAudit.consistency.score}/10 | 25% | ${(tokenAudit.consistency.score * 0.25).toFixed(1)} |
| Accessibility | ${tokenAudit.accessibility.score}/10 | 30% | ${(tokenAudit.accessibility.score * 0.30).toFixed(1)} |
| Completeness | ${tokenAudit.completeness.score}/10 | 25% | ${(tokenAudit.completeness.score * 0.25).toFixed(1)} |
| Quality | ${tokenAudit.quality.score}/10 | 20% | ${(tokenAudit.quality.score * 0.20).toFixed(1)} |

## Critical Issues
${criticalIssues.map(i => `- **[CRITICAL]** ${i.description}\n  Location: ${i.location}\n  Fix: ${i.suggestion}`).join('\n')}

## High Issues
${highIssues.map(i => `- **[HIGH]** ${i.description}\n  Fix: ${i.suggestion}`).join('\n')}

## Medium Issues
${mediumIssues.map(i => `- [MEDIUM] ${i.description}`).join('\n')}

## Recommendations
${recommendations.join('\n')}

## GC Loop Status
- Signal: ${signal}
- ${signal === 'audit_passed' ? '✅ 设计通过审查' : `⚠️ 需要 designer 修订: ${criticalIssues.length + highIssues.length} 个问题需修复`}
`

Write(`${sessionFolder}/audit/audit-${auditNumber}.md`, auditReport)

Phase 4: Validation

// Verify audit report written
try {
  Read(`${sessionFolder}/audit/audit-${auditNumber}.md`)
} catch {
  // Re-write audit report
}

// Cross-reference with previous audits for trend
if (auditHistory.length > 0) {
  const previousScore = auditHistory[auditHistory.length - 1].score
  const trend = overallScore > previousScore ? 'improving' : overallScore === previousScore ? 'stable' : 'declining'
  // Include trend in report
}

Phase 5: Report + Shared Memory Write

// Update shared memory
sharedMemory.audit_history.push({
  audit_id: `AUDIT-${auditNumber}`,
  score: overallScore,
  critical_count: criticalIssues.length,
  signal: signal,
  is_sync_point: isSyncPoint,
  timestamp: new Date().toISOString()
})
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))

// Report to coordinator
mcp__ccw-tools__team_msg({
  operation: "log",
  team: teamName,
  from: "reviewer",
  to: "coordinator",
  type: signal,
  summary: `[reviewer] AUDIT-${auditNumber}: 分数 ${overallScore}/10, 严重问题 ${criticalIssues.length}${isSyncPoint ? ' [同步点]' : ''}`,
  ref: `${sessionFolder}/audit/audit-${auditNumber}.md`
})

SendMessage({
  type: "message",
  recipient: "coordinator",
  content: `## [reviewer] 审查报告 AUDIT-${auditNumber}\n\n- 分数: ${overallScore}/10\n- 信号: ${signal}\n- 严重问题: ${criticalIssues.length}\n- 高级问题: ${highIssues.length}\n${isSyncPoint ? `\n⚡ **同步点**: ${signal === 'audit_passed' ? '通过' : '未通过'}` : ''}\n\n${signal !== 'audit_passed' ? `### 需修复:\n${criticalIssues.concat(highIssues).map(i => `- ${i.description}`).join('\n')}` : ''}`,
  summary: `[reviewer] AUDIT-${auditNumber}: ${overallScore}/10, ${signal}`
})

TaskUpdate({ taskId: task.id, status: 'completed' })

Severity Classification

Severity Criteria GC Impact
CRITICAL 可访问性不合规 (对比度 <3:1), 缺少关键状态 阻塞 GC 收敛
HIGH 令牌引用不一致, 缺少 ARIA 属性, 部分状态缺失 计入 GC 评分
MEDIUM 命名不规范, 文档不完整, 次要样式问题 建议修复
LOW 代码风格, 可选优化 信息性

Error Handling

Scenario Resolution
设计文件不存在 报告 error通知 coordinator
令牌格式无法解析 降级为文本审查
审查维度无法评估 标记为 N/A不计入总分