mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-22 19:18:47 +08:00
refactor: split review responsibilities — code review in lite-execute, convergence review in lite-test-review
- lite-plan LP-Phase 4: split single "Review" into two selections (Code Review + Convergence Review) - lite-execute: add Step 4 Code Review (agent/codex/gemini) with code-review.md artifact, Step 5 passes convergenceReviewTool - lite-test-review: rename reviewTool → convergenceReviewTool, TR-Phase 2 focused on convergence criteria verification - All autoYes paths default both reviews to Skip - Data structures updated across all three files for consistency Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -74,7 +74,7 @@ function selectExecutionOptions() {
|
|||||||
const autoYes = workflowPreferences?.autoYes ?? false
|
const autoYes = workflowPreferences?.autoYes ?? false
|
||||||
|
|
||||||
if (autoYes) {
|
if (autoYes) {
|
||||||
return { execution_method: "Auto", code_review_tool: "Skip" }
|
return { execution_method: "Auto", code_review_tool: "Skip", convergence_review_tool: "Skip" }
|
||||||
}
|
}
|
||||||
|
|
||||||
return AskUserQuestion({
|
return AskUserQuestion({
|
||||||
@@ -90,14 +90,25 @@ function selectExecutionOptions() {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Review tool for test-review phase?",
|
question: "Code review after execution? (runs here in lite-execute)",
|
||||||
header: "Review Tool (passed to lite-test-review)",
|
header: "Code Review",
|
||||||
multiSelect: false,
|
multiSelect: false,
|
||||||
options: [
|
options: [
|
||||||
{ label: "Agent Review", description: "Agent review in test-review (default)" },
|
{ label: "Gemini Review", description: "Gemini CLI: git diff quality review" },
|
||||||
{ label: "Gemini Review", description: "Gemini CLI in test-review" },
|
{ label: "Codex Review", description: "Codex CLI: git-aware code review (--mode review)" },
|
||||||
{ label: "Codex Review", description: "Codex CLI in test-review" },
|
{ label: "Agent Review", description: "@code-reviewer agent" },
|
||||||
{ label: "Skip", description: "Skip review in test-review" }
|
{ label: "Skip", description: "No code review" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Convergence review in test-review phase?",
|
||||||
|
header: "Convergence Review",
|
||||||
|
multiSelect: false,
|
||||||
|
options: [
|
||||||
|
{ label: "Agent", description: "Agent: verify convergence criteria" },
|
||||||
|
{ label: "Gemini", description: "Gemini CLI: convergence verification" },
|
||||||
|
{ label: "Codex", description: "Codex CLI: convergence verification" },
|
||||||
|
{ label: "Skip", description: "Skip convergence review, run tests only" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -117,7 +128,8 @@ if (executionContext) {
|
|||||||
console.log(`
|
console.log(`
|
||||||
Execution Strategy (from lite-plan):
|
Execution Strategy (from lite-plan):
|
||||||
Method: ${executionContext.executionMethod}
|
Method: ${executionContext.executionMethod}
|
||||||
Review: ${executionContext.codeReviewTool}
|
Code Review: ${executionContext.codeReviewTool}
|
||||||
|
Convergence Review: ${executionContext.convergenceReviewTool}
|
||||||
Tasks: ${getTasks(executionContext.planObject).length}
|
Tasks: ${getTasks(executionContext.planObject).length}
|
||||||
Complexity: ${executionContext.planObject.complexity}
|
Complexity: ${executionContext.planObject.complexity}
|
||||||
${executionContext.executorAssignments ? ` Assignments: ${JSON.stringify(executionContext.executorAssignments)}` : ''}
|
${executionContext.executorAssignments ? ` Assignments: ${JSON.stringify(executionContext.executorAssignments)}` : ''}
|
||||||
@@ -367,18 +379,97 @@ ${(t.test?.success_metrics || []).length > 0 ? `**Success metrics**: ${t.test.su
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 4: Chain to Test Review & Post-Completion
|
### Step 4: Code Review
|
||||||
|
|
||||||
> **Note**: Spec sync (session:sync) is handled by lite-test-review's TR-Phase 5, not here. This avoids duplicate sync and ensures test fix changes are also captured.
|
**Skip if**: `codeReviewTool === 'Skip'`
|
||||||
|
|
||||||
**Map review tool**: Convert lite-execute's `codeReviewTool` to test-review tool name.
|
**Resolve review tool**: From `executionContext.codeReviewTool` (Mode 1) or `userSelection.code_review_tool` (Mode 2/3).
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function mapReviewTool(codeReviewTool) {
|
const codeReviewTool = executionContext?.codeReviewTool || userSelection?.code_review_tool || 'Skip'
|
||||||
|
const resolvedTool = (() => {
|
||||||
if (!codeReviewTool || codeReviewTool === 'Skip') return 'skip'
|
if (!codeReviewTool || codeReviewTool === 'Skip') return 'skip'
|
||||||
if (/gemini/i.test(codeReviewTool)) return 'gemini'
|
if (/gemini/i.test(codeReviewTool)) return 'gemini'
|
||||||
if (/codex/i.test(codeReviewTool)) return 'codex'
|
if (/codex/i.test(codeReviewTool)) return 'codex'
|
||||||
return 'agent'
|
return 'agent'
|
||||||
|
})()
|
||||||
|
|
||||||
|
if (resolvedTool === 'skip') {
|
||||||
|
console.log('[Code Review] Skipped')
|
||||||
|
} else {
|
||||||
|
// proceed with review
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Agent Code Review** (resolvedTool === 'agent'):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Agent({
|
||||||
|
subagent_type: "code-reviewer",
|
||||||
|
run_in_background: false,
|
||||||
|
description: `Code review: ${planObject.summary}`,
|
||||||
|
prompt: `## Code Review — Post-Execution Quality Check
|
||||||
|
|
||||||
|
**Goal**: ${originalUserInput}
|
||||||
|
**Plan Summary**: ${planObject.summary}
|
||||||
|
|
||||||
|
### Changed Files
|
||||||
|
Run \`git diff --name-only HEAD~${getTasks(planObject).length}..HEAD\` to identify changes.
|
||||||
|
|
||||||
|
### Review Focus
|
||||||
|
1. **Code quality**: Readability, naming, structure, dead code
|
||||||
|
2. **Correctness**: Logic errors, off-by-one, null handling, edge cases
|
||||||
|
3. **Patterns**: Consistency with existing codebase conventions
|
||||||
|
4. **Security**: Injection, XSS, auth bypass, secrets exposure
|
||||||
|
5. **Performance**: Unnecessary loops, N+1 queries, missing indexes
|
||||||
|
|
||||||
|
### Instructions
|
||||||
|
1. Run git diff to see actual changes
|
||||||
|
2. Read changed files for full context
|
||||||
|
3. For each issue found: severity (Critical/High/Medium/Low) + file:line + description + fix suggestion
|
||||||
|
4. Return structured review: issues[], summary, overall verdict (PASS/WARN/FAIL)`
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**CLI Code Review — Codex** (resolvedTool === 'codex'):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const reviewId = `${sessionId}-code-review`
|
||||||
|
Bash(`ccw cli -p "Review code changes for quality, correctness, security, and pattern compliance. Focus: ${planObject.summary}" --tool codex --mode review --id ${reviewId}`, { run_in_background: true })
|
||||||
|
// STOP - wait for hook callback
|
||||||
|
```
|
||||||
|
|
||||||
|
**CLI Code Review — Gemini** (resolvedTool === 'gemini'):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const reviewId = `${sessionId}-code-review`
|
||||||
|
Bash(`ccw cli -p "PURPOSE: Post-execution code quality review for: ${planObject.summary}
|
||||||
|
TASK: • Run git diff to identify all changes • Review each changed file for quality, correctness, security • Check pattern compliance with existing codebase • Identify potential bugs, edge cases, performance issues
|
||||||
|
MODE: analysis
|
||||||
|
CONTEXT: @**/* | Memory: lite-execute completed, reviewing code quality
|
||||||
|
EXPECTED: Per-file review with severity levels (Critical/High/Medium/Low), file:line references, fix suggestions, overall verdict
|
||||||
|
CONSTRAINTS: Read-only | Focus on code quality not convergence" --tool gemini --mode analysis --rule analysis-review-code-quality --id ${reviewId}`, { run_in_background: true })
|
||||||
|
// STOP - wait for hook callback
|
||||||
|
```
|
||||||
|
|
||||||
|
**Write review artifact** (if session folder exists):
|
||||||
|
```javascript
|
||||||
|
if (executionContext?.session?.folder) {
|
||||||
|
Write(`${executionContext.session.folder}/code-review.md`, codeReviewOutput)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Chain to Test Review & Post-Completion
|
||||||
|
|
||||||
|
**Resolve convergence review tool**: From `executionContext.convergenceReviewTool` (Mode 1) or `userSelection.convergence_review_tool` (Mode 2/3).
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function resolveConvergenceTool(ctx, selection) {
|
||||||
|
const raw = ctx?.convergenceReviewTool || selection?.convergence_review_tool || 'skip'
|
||||||
|
if (!raw || raw === 'Skip') return 'skip'
|
||||||
|
if (/gemini/i.test(raw)) return 'gemini'
|
||||||
|
if (/codex/i.test(raw)) return 'codex'
|
||||||
|
return 'agent'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -389,7 +480,7 @@ testReviewContext = {
|
|||||||
planObject: planObject,
|
planObject: planObject,
|
||||||
taskFiles: executionContext?.taskFiles
|
taskFiles: executionContext?.taskFiles
|
||||||
|| getTasks(planObject).map(t => ({ id: t.id, path: `${executionContext?.session?.folder}/.task/${t.id}.json` })),
|
|| getTasks(planObject).map(t => ({ id: t.id, path: `${executionContext?.session?.folder}/.task/${t.id}.json` })),
|
||||||
reviewTool: mapReviewTool(executionContext?.codeReviewTool),
|
convergenceReviewTool: resolveConvergenceTool(executionContext, userSelection),
|
||||||
executionResults: previousExecutionResults,
|
executionResults: previousExecutionResults,
|
||||||
originalUserInput: originalUserInput,
|
originalUserInput: originalUserInput,
|
||||||
session: executionContext?.session || {
|
session: executionContext?.session || {
|
||||||
@@ -442,7 +533,8 @@ Skill("lite-test-review")
|
|||||||
explorationManifest: {...} | null,
|
explorationManifest: {...} | null,
|
||||||
clarificationContext: {...} | null,
|
clarificationContext: {...} | null,
|
||||||
executionMethod: "Agent" | "Codex" | "Auto",
|
executionMethod: "Agent" | "Codex" | "Auto",
|
||||||
codeReviewTool: "Skip" | "Gemini Review" | "Agent Review" | string,
|
codeReviewTool: "Skip" | "Gemini Review" | "Codex Review" | "Agent Review",
|
||||||
|
convergenceReviewTool: "Skip" | "Agent" | "Gemini" | "Codex",
|
||||||
originalUserInput: string,
|
originalUserInput: string,
|
||||||
executorAssignments: { // per-task override, priority over executionMethod
|
executorAssignments: { // per-task override, priority over executionMethod
|
||||||
[taskId]: { executor: "gemini" | "codex" | "agent", reason: string }
|
[taskId]: { executor: "gemini" | "codex" | "agent", reason: string }
|
||||||
|
|||||||
@@ -492,8 +492,8 @@ ${tasks.map((t, i) => `${i+1}. ${t.title} (${t.scope || t.files?.[0]?.path || ''
|
|||||||
let userSelection
|
let userSelection
|
||||||
|
|
||||||
if (workflowPreferences.autoYes) {
|
if (workflowPreferences.autoYes) {
|
||||||
console.log(`[Auto] Allow & Execute | Auto | Skip`)
|
console.log(`[Auto] Allow & Execute | Auto | Skip + Skip`)
|
||||||
userSelection = { confirmation: "Allow", execution_method: "Auto", code_review_tool: "Skip" }
|
userSelection = { confirmation: "Allow", execution_method: "Auto", code_review_tool: "Skip", convergence_review_tool: "Skip" }
|
||||||
} else {
|
} else {
|
||||||
// "Other" in Execution allows specifying CLI tools from ~/.claude/cli-tools.json
|
// "Other" in Execution allows specifying CLI tools from ~/.claude/cli-tools.json
|
||||||
userSelection = AskUserQuestion({
|
userSelection = AskUserQuestion({
|
||||||
@@ -519,14 +519,25 @@ if (workflowPreferences.autoYes) {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: "Code review after execution?",
|
question: "Code review after execution? (runs in lite-execute)",
|
||||||
header: "Review",
|
header: "Code Review",
|
||||||
multiSelect: false,
|
multiSelect: false,
|
||||||
options: [
|
options: [
|
||||||
{ label: "Gemini Review", description: "Gemini CLI review" },
|
{ label: "Gemini Review", description: "Gemini CLI: git diff quality review" },
|
||||||
{ label: "Codex Review", description: "Git-aware review (prompt OR --uncommitted)" },
|
{ label: "Codex Review", description: "Codex CLI: git-aware code review (--mode review)" },
|
||||||
{ label: "Agent Review", description: "@code-reviewer agent" },
|
{ label: "Agent Review", description: "@code-reviewer agent" },
|
||||||
{ label: "Skip", description: "No review" }
|
{ label: "Skip", description: "No code review" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Convergence review in test-review phase?",
|
||||||
|
header: "Convergence Review",
|
||||||
|
multiSelect: false,
|
||||||
|
options: [
|
||||||
|
{ label: "Agent", description: "Agent: verify convergence criteria against implementation" },
|
||||||
|
{ label: "Gemini", description: "Gemini CLI: convergence verification" },
|
||||||
|
{ label: "Codex", description: "Codex CLI: convergence verification" },
|
||||||
|
{ label: "Skip", description: "Skip convergence review, run tests only" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -534,7 +545,7 @@ if (workflowPreferences.autoYes) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
// TodoWrite: Phase 4 → completed `[${userSelection.execution_method} + ${userSelection.code_review_tool}]`, Phase 5 → in_progress
|
// TodoWrite: Phase 4 → completed `[${userSelection.execution_method} | CR:${userSelection.code_review_tool} | CVR:${userSelection.convergence_review_tool}]`, Phase 5 → in_progress
|
||||||
|
|
||||||
## 10. LP-Phase 5: Handoff to Execution
|
## 10. LP-Phase 5: Handoff to Execution
|
||||||
|
|
||||||
@@ -561,6 +572,7 @@ executionContext = {
|
|||||||
clarificationContext: clarificationContext || null,
|
clarificationContext: clarificationContext || null,
|
||||||
executionMethod: userSelection.execution_method,
|
executionMethod: userSelection.execution_method,
|
||||||
codeReviewTool: userSelection.code_review_tool,
|
codeReviewTool: userSelection.code_review_tool,
|
||||||
|
convergenceReviewTool: userSelection.convergence_review_tool,
|
||||||
originalUserInput: task_description,
|
originalUserInput: task_description,
|
||||||
executorAssignments: executorAssignments, // { taskId: { executor, reason } } — overrides executionMethod
|
executorAssignments: executorAssignments, // { taskId: { executor, reason } } — overrides executionMethod
|
||||||
session: {
|
session: {
|
||||||
@@ -588,7 +600,7 @@ TodoWrite({ todos: [
|
|||||||
{ content: "LP-Phase 1: Exploration", status: "completed" },
|
{ content: "LP-Phase 1: Exploration", status: "completed" },
|
||||||
{ content: "LP-Phase 2: Clarification", status: "completed" },
|
{ content: "LP-Phase 2: Clarification", status: "completed" },
|
||||||
{ content: "LP-Phase 3: Planning", status: "completed" },
|
{ content: "LP-Phase 3: Planning", status: "completed" },
|
||||||
{ content: `LP-Phase 4: Confirmed [${userSelection.execution_method}]`, status: "completed" },
|
{ content: `LP-Phase 4: Confirmed [${userSelection.execution_method} | CR:${userSelection.code_review_tool} | CVR:${userSelection.convergence_review_tool}]`, status: "completed" },
|
||||||
{ content: `LP-Phase 5: Handoff → lite-execute`, status: "completed" },
|
{ content: `LP-Phase 5: Handoff → lite-execute`, status: "completed" },
|
||||||
{ content: `LE-Phase 1: Task Loading [${taskCount} tasks]`, status: "in_progress", activeForm: "Loading tasks" }
|
{ content: `LE-Phase 1: Task Loading [${taskCount} tasks]`, status: "in_progress", activeForm: "Loading tasks" }
|
||||||
]})
|
]})
|
||||||
@@ -605,6 +617,7 @@ Skill("lite-execute")
|
|||||||
├── explorations-manifest.json # Exploration index
|
├── explorations-manifest.json # Exploration index
|
||||||
├── planning-context.md # Evidence paths + understanding
|
├── planning-context.md # Evidence paths + understanding
|
||||||
├── plan.json # Plan overview (task_ids[])
|
├── plan.json # Plan overview (task_ids[])
|
||||||
|
├── code-review.md # Generated by lite-execute Step 4
|
||||||
├── test-checklist.json # Generated by lite-test-review
|
├── test-checklist.json # Generated by lite-test-review
|
||||||
├── test-review.md # Generated by lite-test-review
|
├── test-review.md # Generated by lite-test-review
|
||||||
└── .task/
|
└── .task/
|
||||||
@@ -618,9 +631,12 @@ Skill("lite-execute")
|
|||||||
```
|
```
|
||||||
lite-plan (LP-Phase 1-5)
|
lite-plan (LP-Phase 1-5)
|
||||||
└─ Skill("lite-execute") ← executionContext (global)
|
└─ Skill("lite-execute") ← executionContext (global)
|
||||||
├─ Step 1-4: Execute + Review
|
├─ Step 1-3: Task Execution
|
||||||
|
├─ Step 4: Code Review (quality/correctness/security)
|
||||||
└─ Step 5: Skill("lite-test-review") ← testReviewContext (global)
|
└─ Step 5: Skill("lite-test-review") ← testReviewContext (global)
|
||||||
├─ TR-Phase 1-4: Test + Fix
|
├─ TR-Phase 1: Detect test framework
|
||||||
|
├─ TR-Phase 2: Convergence verification (plan criteria)
|
||||||
|
├─ TR-Phase 3-4: Run tests + Auto-fix
|
||||||
└─ TR-Phase 5: Report + Sync specs
|
└─ TR-Phase 5: Report + Sync specs
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -31,31 +31,31 @@ Test review and fix engine for lite-execute chain or standalone invocation.
|
|||||||
|
|
||||||
**Input Source**: `testReviewContext` global variable set by lite-execute Step 4
|
**Input Source**: `testReviewContext` global variable set by lite-execute Step 4
|
||||||
|
|
||||||
**Behavior**: Skip session discovery, inherit reviewTool from execution chain, proceed directly to TR-Phase 1.
|
**Behavior**: Skip session discovery, inherit convergenceReviewTool from execution chain, proceed directly to TR-Phase 1.
|
||||||
|
|
||||||
> **Note**: lite-execute Step 4 is the chain gate. Mode 1 invocation means execution is complete — proceed with test review.
|
> **Note**: lite-execute Step 5 is the chain gate. Mode 1 invocation means execution + code review are complete — proceed with convergence verification + tests.
|
||||||
|
|
||||||
### Mode 2: Standalone
|
### Mode 2: Standalone
|
||||||
|
|
||||||
**Trigger**: User calls with session path or `--last`
|
**Trigger**: User calls with session path or `--last`
|
||||||
|
|
||||||
**Behavior**: Discover session → load plan + tasks → `reviewTool = 'agent'` → proceed to TR-Phase 1.
|
**Behavior**: Discover session → load plan + tasks → `convergenceReviewTool = 'agent'` → proceed to TR-Phase 1.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let sessionPath, plan, taskFiles, reviewTool
|
let sessionPath, plan, taskFiles, convergenceReviewTool
|
||||||
|
|
||||||
if (testReviewContext) {
|
if (testReviewContext) {
|
||||||
// Mode 1: from lite-execute chain
|
// Mode 1: from lite-execute chain
|
||||||
sessionPath = testReviewContext.session.folder
|
sessionPath = testReviewContext.session.folder
|
||||||
plan = testReviewContext.planObject
|
plan = testReviewContext.planObject
|
||||||
taskFiles = testReviewContext.taskFiles.map(tf => JSON.parse(Read(tf.path)))
|
taskFiles = testReviewContext.taskFiles.map(tf => JSON.parse(Read(tf.path)))
|
||||||
reviewTool = testReviewContext.reviewTool || 'agent'
|
convergenceReviewTool = testReviewContext.convergenceReviewTool || 'agent'
|
||||||
} else {
|
} else {
|
||||||
// Mode 2: standalone — find last session or use provided path
|
// Mode 2: standalone — find last session or use provided path
|
||||||
sessionPath = resolveSessionPath($ARGUMENTS) // Glob('.workflow/.lite-plan/*/plan.json'), take last
|
sessionPath = resolveSessionPath($ARGUMENTS) // Glob('.workflow/.lite-plan/*/plan.json'), take last
|
||||||
plan = JSON.parse(Read(`${sessionPath}/plan.json`))
|
plan = JSON.parse(Read(`${sessionPath}/plan.json`))
|
||||||
taskFiles = plan.task_ids.map(id => JSON.parse(Read(`${sessionPath}/.task/${id}.json`)))
|
taskFiles = plan.task_ids.map(id => JSON.parse(Read(`${sessionPath}/.task/${id}.json`)))
|
||||||
reviewTool = 'agent'
|
convergenceReviewTool = 'agent'
|
||||||
}
|
}
|
||||||
|
|
||||||
const skipFix = $ARGUMENTS?.includes('--skip-fix') || false
|
const skipFix = $ARGUMENTS?.includes('--skip-fix') || false
|
||||||
@@ -66,7 +66,7 @@ const skipFix = $ARGUMENTS?.includes('--skip-fix') || false
|
|||||||
| Phase | Core Action | Output |
|
| Phase | Core Action | Output |
|
||||||
|-------|-------------|--------|
|
|-------|-------------|--------|
|
||||||
| TR-Phase 1 | Detect test framework + gather changes | testConfig, changedFiles |
|
| TR-Phase 1 | Detect test framework + gather changes | testConfig, changedFiles |
|
||||||
| TR-Phase 2 | Review implementation against convergence criteria | reviewResults[] |
|
| TR-Phase 2 | Convergence verification against plan criteria | reviewResults[] |
|
||||||
| TR-Phase 3 | Run tests + generate checklist | test-checklist.json |
|
| TR-Phase 3 | Run tests + generate checklist | test-checklist.json |
|
||||||
| TR-Phase 4 | Auto-fix failures (iterative, max 3 rounds) | Fixed code + updated checklist |
|
| TR-Phase 4 | Auto-fix failures (iterative, max 3 rounds) | Fixed code + updated checklist |
|
||||||
| TR-Phase 5 | Output report + chain to session:sync | test-review.md |
|
| TR-Phase 5 | Output report + chain to session:sync | test-review.md |
|
||||||
@@ -93,32 +93,45 @@ Output: `testConfig = { command, framework, type }` + `changedFiles[]`
|
|||||||
|
|
||||||
// TodoWrite: Phase 1 → completed, Phase 2 → in_progress
|
// TodoWrite: Phase 1 → completed, Phase 2 → in_progress
|
||||||
|
|
||||||
## TR-Phase 2: Review Implementation Against Plan
|
## TR-Phase 2: Convergence Verification
|
||||||
|
|
||||||
**Skip if**: `reviewTool === 'skip'` — set all tasks to PASS, proceed to Phase 3.
|
**Skip if**: `convergenceReviewTool === 'skip'` — set all tasks to PASS, proceed to Phase 3.
|
||||||
|
|
||||||
For each task, verify convergence criteria and identify test gaps.
|
Verify each task's convergence criteria are met in the implementation and identify test gaps.
|
||||||
|
|
||||||
**Agent Review** (reviewTool === 'agent', default):
|
**Agent Convergence Review** (convergenceReviewTool === 'agent', default):
|
||||||
|
|
||||||
For each task in taskFiles:
|
For each task in taskFiles:
|
||||||
1. Extract `convergence.criteria[]` and `test` requirements
|
1. Extract `convergence.criteria[]` from the task
|
||||||
2. Find changed files matching `task.files[].path` against `changedFiles`
|
2. Match `task.files[].path` against `changedFiles` to find actually-changed files
|
||||||
3. Read matched files, evaluate each criterion against implementation
|
3. Read each matched file, verify each convergence criterion with file:line evidence
|
||||||
4. Check test coverage: if `task.test.unit` exists but no test files in changedFiles → mark as test gap
|
4. Check test coverage gaps:
|
||||||
5. Same for `task.test.integration`
|
- If `task.test.unit` defined but no matching test files in changedFiles → mark as test gap
|
||||||
6. Build `reviewResult = { taskId, title, criteria_met[], criteria_unmet[], test_gaps[], files_reviewed[] }`
|
- If `task.test.integration` defined but no integration test in changedFiles → mark as test gap
|
||||||
|
5. Build `reviewResult = { taskId, title, criteria_met[], criteria_unmet[], test_gaps[], files_reviewed[] }`
|
||||||
|
|
||||||
**CLI Review** (reviewTool === 'gemini' or 'codex'):
|
**Verdict logic**:
|
||||||
|
- PASS = all `convergence.criteria` met + no test gaps
|
||||||
|
- PARTIAL = some criteria met OR has test gaps
|
||||||
|
- FAIL = no criteria met
|
||||||
|
|
||||||
|
**CLI Convergence Review** (convergenceReviewTool === 'gemini' or 'codex'):
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const reviewId = `${sessionId}-tr-review`
|
const reviewId = `${sessionId}-convergence`
|
||||||
Bash(`ccw cli -p "PURPOSE: Post-execution test review — verify convergence criteria met and identify test gaps
|
const taskCriteria = taskFiles.map(t => `${t.id}: [${(t.convergence?.criteria || []).join(' | ')}]`).join('\n')
|
||||||
TASK: • Read plan.json and .task/*.json convergence criteria • For each criterion, check implementation in changed files • Identify missing unit/integration tests • List unmet criteria with file:line evidence
|
Bash(`ccw cli -p "PURPOSE: Convergence verification — check each task's completion criteria against actual implementation
|
||||||
|
TASK: • For each task below, verify every convergence criterion is satisfied in the changed files • Mark each criterion as MET (with file:line evidence) or UNMET (with what's missing) • Identify test coverage gaps (planned tests not found in changes)
|
||||||
|
|
||||||
|
TASK CRITERIA:
|
||||||
|
${taskCriteria}
|
||||||
|
|
||||||
|
CHANGED FILES: ${changedFiles.join(', ')}
|
||||||
|
|
||||||
MODE: analysis
|
MODE: analysis
|
||||||
CONTEXT: @${sessionPath}/plan.json @${sessionPath}/.task/*.json @**/* | Memory: lite-execute completed, reviewing convergence
|
CONTEXT: @${sessionPath}/plan.json @${sessionPath}/.task/*.json @**/* | Memory: lite-execute completed
|
||||||
EXPECTED: Per-task verdict table (PASS/PARTIAL/FAIL) + unmet criteria list + test gap list
|
EXPECTED: Per-task verdict (PASS/PARTIAL/FAIL) with per-criterion evidence + test gap list
|
||||||
CONSTRAINTS: Read-only | Focus on convergence verification" --tool ${reviewTool} --mode analysis --id ${reviewId}`, { run_in_background: true })
|
CONSTRAINTS: Read-only | Focus strictly on convergence criteria verification, NOT code quality (code review already done in lite-execute)" --tool ${convergenceReviewTool} --mode analysis --id ${reviewId}`, { run_in_background: true })
|
||||||
// STOP - wait for hook callback, then parse CLI output into reviewResults format
|
// STOP - wait for hook callback, then parse CLI output into reviewResults format
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -207,13 +220,13 @@ Skill({ skill: "workflow:session:sync", args: `-y "Test review: ${testChecklist.
|
|||||||
|
|
||||||
## Data Structures
|
## Data Structures
|
||||||
|
|
||||||
### testReviewContext (Input - Mode 1, set by lite-execute)
|
### testReviewContext (Input - Mode 1, set by lite-execute Step 5)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
planObject: { /* same as executionContext.planObject */ },
|
planObject: { /* same as executionContext.planObject */ },
|
||||||
taskFiles: [{ id: string, path: string }],
|
taskFiles: [{ id: string, path: string }],
|
||||||
reviewTool: "skip" | "agent" | "gemini" | "codex",
|
convergenceReviewTool: "skip" | "agent" | "gemini" | "codex",
|
||||||
executionResults: [...],
|
executionResults: [...],
|
||||||
originalUserInput: string,
|
originalUserInput: string,
|
||||||
session: {
|
session: {
|
||||||
|
|||||||
Reference in New Issue
Block a user