ALEPH HUB
/EN
提交
← 返回
L
Communityworkflow

Lights-Out Development Pipeline

固定 9 阶段的 Claude Code 工作流,把一句需求变成可交付代码——依次走规格、设计、架构、一致性、测试设计、实现、QA、端到端验证与最终核查循环,每个产物都经过独立的「写→评审→修」对抗式回路。

概览安全

编排一条线性的受监督子代理流水线(spec-writer/reviewer、ux-designer、architect、consistency-reviewer、test-case-designer、code-agent、qa-engineer、bug-fixer、visual-qa),各自从 ~/.claude/lights-out/prompts 读取角色提示。规格/设计/架构/测试用例文档写入 docs/ 并按 MAX_ROUNDS 反复评审;QA 与端到端各跑有上限的修复循环,最后用「冻结缺陷清单」的终检验证代码相对文档的完整性、正确性与一致性。

export const meta = {
  name: 'lightsout-workflow',
  description: 'Lights-out development pipeline: one sentence in, production code out. Fixed linear pipeline — every phase runs, agents self-calibrate depth.',
  phases: [
    { title: 'Spec', detail: 'Write/update product specification + independent review' },
    { title: 'Design', detail: 'Write/update interaction design + independent review' },
    { title: 'Architecture', detail: 'Write/update technical architecture + independent review' },
    { title: 'Consistency', detail: 'Cross-document consistency check' },
    { title: 'Test Design', detail: 'Design test cases before implementation' },
    { title: 'Code', detail: 'Implementation orchestrator (manages parallelism internally)' },
    { title: 'QA', detail: 'Automated tests + logical walkthrough + test quality audit' },
    { title: 'E2E Verification', detail: 'Launch app, Playwright browser testing, visual + functional verification' },
    { title: 'Final Check', detail: 'Three-dimensional verification + fix loop' },
  ],
}

// === Schemas ===

const REVIEW_SCHEMA = {
  type: 'object',
  properties: {
    approved: { type: 'boolean' },
    issues: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          severity: { type: 'string', enum: ['critical', 'major', 'minor'] },
          issue: { type: 'string' },
          suggestion: { type: 'string' },
        },
        required: ['severity', 'issue', 'suggestion'],
      },
    },
    verdict: { type: 'string' },
  },
  required: ['approved', 'issues', 'verdict'],
}

const CONSISTENCY_SCHEMA = {
  type: 'object',
  properties: {
    consistent: { type: 'boolean' },
    conflicts: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          doc_a: { type: 'string' },
          doc_b: { type: 'string' },
          quote_a: { type: 'string' },
          quote_b: { type: 'string' },
          resolution: { type: 'string' },
        },
        required: ['doc_a', 'doc_b', 'quote_a', 'quote_b', 'resolution'],
      },
    },
    verdict: { type: 'string' },
  },
  required: ['consistent', 'conflicts', 'verdict'],
}

const QA_SCHEMA = {
  type: 'object',
  properties: {
    all_passed: { type: 'boolean' },
    summary: { type: 'string' },
    issues: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          file: { type: 'string' },
          test_name: { type: 'string' },
          error: { type: 'string' },
          likely_source: { type: 'string' },
          fix_hint: { type: 'string' },
        },
        required: ['file', 'test_name', 'error', 'fix_hint'],
      },
    },
  },
  required: ['all_passed', 'summary', 'issues'],
}

const E2E_SCHEMA = {
  type: 'object',
  properties: {
    passed: { type: 'boolean' },
    project_type: { type: 'string', enum: ['web', 'cli', 'api', 'library'] },
    visual_issues: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          severity: { type: 'string', enum: ['critical', 'major', 'minor'] },
          component: { type: 'string' },
          issue: { type: 'string' },
          fix_suggestion: { type: 'string' },
        },
        required: ['severity', 'component', 'issue', 'fix_suggestion'],
      },
    },
    functional_issues: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          severity: { type: 'string', enum: ['critical', 'major', 'minor'] },
          flow: { type: 'string' },
          issue: { type: 'string' },
          fix_suggestion: { type: 'string' },
        },
        required: ['severity', 'flow', 'issue', 'fix_suggestion'],
      },
    },
    verdict: { type: 'string' },
  },
  required: ['passed', 'project_type', 'visual_issues', 'functional_issues', 'verdict'],
}

const FINAL_CHECK_SCHEMA = {
  type: 'object',
  properties: {
    passed: { type: 'boolean' },
    completeness: { type: 'boolean' },
    correctness: { type: 'boolean' },
    coherence: { type: 'boolean' },
    gaps: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          dimension: { type: 'string', enum: ['completeness', 'correctness', 'coherence'] },
          requirement: { type: 'string' },
          gap: { type: 'string' },
          affected_files: { type: 'array', items: { type: 'string' } },
          action: { type: 'string' },
        },
        required: ['dimension', 'requirement', 'gap', 'affected_files', 'action'],
      },
    },
    verdict: { type: 'string' },
  },
  required: ['passed', 'completeness', 'correctness', 'coherence', 'gaps', 'verdict'],
}

// === Constants ===
const MAX_ROUNDS = 5
const PROMPTS_DIR = '~/.claude/lights-out/prompts'
const PROJECT_DIR = args.project_dir || '.'

// === Pipeline State ===
const state = {
  request: args.request,
  brief: args.brief || null,
  project_dir: PROJECT_DIR,
  currentPhase: '',
  phaseResults: []
}

// === Core: Supervised agent call ===
async function supervised(role, task, loopContext, opts = {}) {
  // Only pass the last result per phase + current phase full history to avoid prompt bloat
  const relevantResults = []
  const seenPhases = new Set()
  for (let i = state.phaseResults.length - 1; i >= 0; i--) {
    const r = state.phaseResults[i]
    if (r.phase === state.currentPhase) {
      relevantResults.unshift(r)
    } else if (!seenPhases.has(r.phase)) {
      seenPhases.add(r.phase)
      relevantResults.unshift(r)
    }
  }

  const supPrompt = `Read your instructions from ${PROMPTS_DIR}/supervisor.md.

PIPELINE STATE:
${JSON.stringify({ request: state.request, brief: state.brief, currentPhase: state.currentPhase, phaseResults: relevantResults, loopContext }, null, 2)}

NEXT AGENT:
- Role: ${role}
- Role file: ${PROMPTS_DIR}/${role}.md (read it to understand capabilities)
- Task: ${task}
- Working directory: ${state.project_dir}`

  const brief = await agent(supPrompt, { label: `sup:${role}${loopContext.round ? ':r' + loopContext.round : ''}` })

  const workerPrompt = `Read your instructions from ${PROMPTS_DIR}/${role}.md.

${brief}

Working directory: ${state.project_dir}`

  if (opts.schema) {
    return await agent(workerPrompt, { label: opts.label || role, schema: opts.schema })
  }
  return await agent(workerPrompt, { label: opts.label || role })
}

// === Write + Review loop (pure orchestration) ===
async function writeAndReview(phaseName, writerRole, reviewerRole, docFile) {
  let approved = false
  let round = 0
  let previousIssues = []

  while (!approved && round < MAX_ROUNDS) {
    round++

    const writerTask = round === 1
      ? `Create or update docs/${docFile}. This is the initial draft.`
      : `Revise docs/${docFile} based on reviewer feedback.`

    await supervised(writerRole, writerTask, { round, previousIssues, phase: phaseName })

    const reviewerTask = `Review docs/${docFile}.`
    const review = await supervised(reviewerRole, reviewerTask,
      { round, previousIssues, phase: phaseName },
      { schema: REVIEW_SCHEMA, label: `${reviewerRole}:r${round}` })

    previousIssues = review.issues || []
    state.phaseResults.push({
      phase: phaseName,
      agent: reviewerRole,
      round,
      outcome: review.approved ? 'approved' : 'rejected',
      structured: review
    })

    if (review.approved) {
      approved = true
      log(`${phaseName} approved (round ${round})`)
    } else if (round >= MAX_ROUNDS) {
      log(`${phaseName}: proceeding after ${MAX_ROUNDS} rounds`)
    } else {
      const critical = previousIssues.filter(i => i.severity === 'critical').length
      log(`${phaseName} round ${round}: ${critical} critical issues. Fixing...`)
    }
  }
}

// === Ensure git has at least one commit ===
await agent(
  `Check if git has commits (git rev-parse HEAD). If not: git init (if needed), git add -A && git commit -m "chore: initial scaffold" --allow-empty. Report briefly.\n\nWorking directory: ${PROJECT_DIR}`,
  { label: 'git-check' }
)

// === Phase 1: Spec ===
phase('Spec')
state.currentPhase = 'Spec'
log('Spec phase...')
await writeAndReview('Spec', 'spec-writer', 'spec-reviewer', 'spec.md')

// === Phase 2: Design ===
phase('Design')
state.currentPhase = 'Design'
log('Design phase...')
await writeAndReview('Design', 'ux-designer', 'design-reviewer', 'design.md')

// === Phase 3: Architecture ===
phase('Architecture')
state.currentPhase = 'Architecture'
log('Architecture phase...')
await writeAndReview('Architecture', 'architect', 'arch-reviewer', 'architecture.md')

// === Phase 4: Consistency ===
phase('Consistency')
state.currentPhase = 'Consistency'
log('Cross-document consistency check...')

const consistency = await supervised('consistency-reviewer',
  'Cross-document consistency check: verify spec, design, and architecture agree at the behavioral level.',
  { phase: 'Consistency' },
  { schema: CONSISTENCY_SCHEMA, label: 'consistency:cross-doc' })

state.phaseResults.push({ phase: 'Consistency', agent: 'consistency-reviewer', round: 1, outcome: consistency.consistent ? 'consistent' : 'conflicts', structured: consistency })

if (!consistency.consistent && (consistency.conflicts || []).length > 0) {
  log(`${consistency.conflicts.length} conflicts found. Fixing...`)
  await supervised('consistency-reviewer',
    `Fix these document conflicts. Spec is source of truth.\n\nConflicts:\n${consistency.conflicts.map(c => `- ${c.doc_a} says: "${c.quote_a}"\n  ${c.doc_b} says: "${c.quote_b}"\n  Fix: ${c.resolution}`).join('\n\n')}`,
    { phase: 'Consistency', task: 'fix' },
    { label: 'consistency:fixer' })
}

// === Phase 5: Test Case Design ===
phase('Test Design')
state.currentPhase = 'Test Design'
log('Designing test cases...')

await supervised('test-case-designer',
  'Design test cases before implementation. Read all docs and produce docs/test-cases.md.',
  { phase: 'Test Design' },
  { label: 'test-case-designer' })

// === Phase 6: Code ===
phase('Code')
state.currentPhase = 'Code'
log('Implementation phase...')

await supervised('code-agent',
  `Implement the project. Read docs/spec.md, docs/design.md, docs/architecture.md, docs/test-cases.md. Follow TDD: create test skeletons first, then implement. Commit when done.`,
  { phase: 'Code' },
  { label: 'code-orchestrator' })

// === Phase 7: QA ===
phase('QA')
state.currentPhase = 'QA'
log('QA verification...')

let testsPassed = false
let testRound = 0

while (!testsPassed && testRound < MAX_ROUNDS) {
  testRound++

  const qa = await supervised('qa-engineer',
    testRound === 1
      ? 'Run tests, audit quality, verify coverage.'
      : `QA round ${testRound}. Previous round found failures that should now be fixed.`,
    { phase: 'QA', round: testRound },
    { schema: QA_SCHEMA, label: `qa:r${testRound}` })

  state.phaseResults.push({ phase: 'QA', agent: 'qa-engineer', round: testRound, outcome: qa.all_passed ? 'passed' : 'failed', structured: qa })

  if (qa.all_passed) {
    testsPassed = true
    log(`QA passed (round ${testRound})`)
  } else if (testRound >= MAX_ROUNDS) {
    log(`QA still failing after ${MAX_ROUNDS} rounds. Proceeding.`)
  } else {
    log(`QA round ${testRound}: ${qa.issues.length} issues. Fixing...`)
    await supervised('bug-fixer',
      `Fix these test failures:\n${qa.issues.map(i => `- [${i.file}] ${i.test_name}: ${i.error}\n  Source: ${i.likely_source}\n  Hint: ${i.fix_hint}`).join('\n')}`,
      { phase: 'QA', round: testRound, issues: qa.issues },
      { label: `bug-fixer:r${testRound}` })
  }
}

// === Phase 8: E2E Verification ===
phase('E2E Verification')
state.currentPhase = 'E2E Verification'
log('E2E verification...')

let e2ePassed = false
let e2eRound = 0

while (!e2ePassed && e2eRound < MAX_ROUNDS) {
  e2eRound++

  const e2e = await supervised('visual-qa',
    e2eRound === 1
      ? 'Launch app, verify visual quality and functional flows with Playwright.'
      : `E2E round ${e2eRound}. Previous issues should be fixed.`,
    { phase: 'E2E', round: e2eRound },
    { schema: E2E_SCHEMA, label: `e2e:r${e2eRound}` })

  state.phaseResults.push({ phase: 'E2E', agent: 'visual-qa', round: e2eRound, outcome: e2e.passed ? 'passed' : 'issues', structured: e2e })

  if (e2e.passed) {
    e2ePassed = true
    log(`E2E passed (round ${e2eRound})`)
  } else if (e2eRound >= MAX_ROUNDS) {
    log(`E2E still has issues after ${MAX_ROUNDS} rounds. Proceeding.`)
  } else {
    const issues = [...(e2e.visual_issues || []), ...(e2e.functional_issues || [])]
    log(`E2E round ${e2eRound}: ${issues.length} issues. Fixing...`)
    await supervised('bug-fixer',
      `Fix E2E issues:\n\nVisual:\n${(e2e.visual_issues || []).map(i => `- [${i.severity}] ${i.component}: ${i.issue} → ${i.fix_suggestion}`).join('\n')}\n\nFunctional:\n${(e2e.functional_issues || []).map(i => `- [${i.severity}] ${i.flow}: ${i.issue} → ${i.fix_suggestion}`).join('\n')}\n\nRun tests after fixing. Commit changes.`,
      { phase: 'E2E', round: e2eRound, issues },
      { label: `e2e-fixer:r${e2eRound}` })
  }
}

// === Phase 9: Final Check ===
phase('Final Check')
state.currentPhase = 'Final Check'
log('Three-dimensional verification...')

const initialCheck = await supervised('consistency-reviewer',
  'Doc-vs-code verification: COMPLETENESS (every CAP has impl + test), CORRECTNESS (impl matches spec), COHERENCE (architecture matches actual structure). Only report REAL gaps.',
  { phase: 'Final Check' },
  { schema: FINAL_CHECK_SCHEMA, label: 'final-check:scan' })

let finalPassed = initialCheck.passed
const frozenGaps = initialCheck.gaps || []

state.phaseResults.push({ phase: 'Final Check', agent: 'consistency-reviewer', round: 1, outcome: finalPassed ? 'passed' : 'gaps', structured: initialCheck })

if (finalPassed) {
  log('Final check passed (round 1)')
} else {
  log(`Final check: ${frozenGaps.length} gaps found. Fixing (gap list frozen)...`)

  let fixRound = 0
  const MAX_FIX_ROUNDS = 3

  while (!finalPassed && fixRound < MAX_FIX_ROUNDS) {
    fixRound++

    await supervised('bug-fixer',
      `Fix these FROZEN gaps (only these, nothing else):\n${frozenGaps.map(g => `- [${g.dimension}] ${g.requirement}: ${g.gap}\n  Files: ${g.affected_files.join(', ')}\n  Action: ${g.action}`).join('\n\n')}\n\nRules: only touch listed files, run tests after each fix, revert if tests break. Commit when done.`,
      { phase: 'Final Check', round: fixRound, frozenGaps },
      { label: `final-fixer:r${fixRound}` })

    const recheck = await supervised('consistency-reviewer',
      `Re-verify ONLY these previously-identified gaps (do NOT scan for new issues):\n${frozenGaps.map(g => `- [${g.dimension}] ${g.requirement}: ${g.gap}`).join('\n')}\n\nFor each: CLOSED or OPEN. Report passed=true only if ALL closed.`,
      { phase: 'Final Check', round: fixRound, frozenGaps },
      { schema: FINAL_CHECK_SCHEMA, label: `final-recheck:r${fixRound}` })

    if (recheck.passed) {
      finalPassed = true
      log(`Final check passed after ${fixRound} fix round(s)`)
    } else {
      const remaining = (recheck.gaps || []).length
      log(`Final check: ${remaining}/${frozenGaps.length} gaps remain after round ${fixRound}`)
    }
  }

  if (!finalPassed) {
    log(`Final check: some gaps remain after ${MAX_FIX_ROUNDS} rounds. Completing.`)
  }
}

// === Done ===
log(`Pipeline ${finalPassed && testsPassed && e2ePassed ? 'PASSED' : 'COMPLETED'}. ${args.request}`)

return {
  request: args.request,
  tests_passed: testsPassed,
  test_rounds: testRound,
  e2e_passed: e2ePassed,
  e2e_rounds: e2eRound,
  final_check_passed: finalPassed,
  final_check_gaps_found: frozenGaps.length,
  passed: testsPassed && e2ePassed && finalPassed,
}
#workflow#pipeline#qa#agents#tdd
相关推荐
Coherence Coach
AWeirdDev
Community

监看对话,找出助手可能忽略的上下文,仅在确有必要时给出提醒,否则返回 null。

promptmarkdown
React + Tailwind Product Card Component Prompt
AmirMotefaker
Community

让模型扮演资深前端工程师,生成可用于生产环境、响应式的 React + Tailwind CSS 商品卡片组件(TypeScript)。

promptmarkdown
Secure JWT Authentication Middleware
AmirMotefaker
Community

一个「角色/任务/规则」结构的提示词模板,要求模型为 Node.js + Express 设计安全的 JWT 认证中间件,包含 bcrypt 密码哈希与完整错误处理。

promptmarkdown