Files
Claude-Code-Workflow/.claude/skills/workflow-plan/phases/03-conflict-resolution.md
catlog22 357f48a0c3 chore: batch update - cleanup ghost commands, ccw-help index refresh, CLI session/orchestrator enhancements, skill minor fixes
- Add cleanup-ghost-commands.mjs script
- Refresh ccw-help index files (remove stale entries)
- CLI session manager: add instruction assembler and launch registry
- Frontend: orchestrator plan builder, property panel, dashboard toolbar updates
- Flow executor and type updates
- Minor fixes across multiple skills and commands
2026-02-17 21:53:51 +08:00

16 KiB

Phase 3: Conflict Resolution

Detect and resolve conflicts with CLI analysis. This phase is conditional - only executes when conflict_risk >= medium.

Objective

  • Detect conflicts between planned changes and existing codebase
  • Detect module scenario uniqueness (functional overlaps)
  • Present conflicts to user with resolution strategies
  • Apply selected resolution strategies
  • Update planning-notes.md with conflict decisions

Trigger Condition

Only execute when context-package.json indicates conflict_risk is "medium" or "high". If conflict_risk is "none" or "low", skip directly to Phase 4.

Conflict Categories

Category Description
Architecture Incompatible design patterns, module structure changes
API Breaking contract changes, signature modifications
Data Model Schema modifications, type breaking changes
Dependency Version incompatibilities, setup conflicts
ModuleOverlap Functional overlap, scenario boundary ambiguity, duplicate responsibility

Execution

Step 3.1: Validation

// 1. Verify session directory exists
const sessionDir = `.workflow/active/${sessionId}`;
if (!file_exists(sessionDir)) {
  throw new Error(`Session directory not found: ${sessionDir}`);
}

// 2. Load context-package.json
const contextPackage = JSON.parse(Read(contextPath));

// 3. Check conflict_risk (skip if none/low)
const conflictRisk = contextPackage.conflict_detection?.risk_level || 'low';
if (conflictRisk === 'none' || conflictRisk === 'low') {
  console.log("No significant conflicts detected, proceeding to task generation");
  // Skip directly to Phase 4
  return;
}

Step 3.2: CLI-Powered Conflict Analysis

Agent Delegation:

Task(subagent_type="cli-execution-agent", run_in_background=false, prompt=`
  ## Context
  - Session: ${sessionId}
  - Risk: ${conflictRisk}
  - Files: ${existing_files_list}

  ## Exploration Context (from context-package.exploration_results)
  - Exploration Count: ${contextPackage.exploration_results?.exploration_count || 0}
  - Angles Analyzed: ${JSON.stringify(contextPackage.exploration_results?.angles || [])}
  - Pre-identified Conflict Indicators: ${JSON.stringify(contextPackage.exploration_results?.aggregated_insights?.conflict_indicators || [])}
  - Critical Files: ${JSON.stringify(contextPackage.exploration_results?.aggregated_insights?.critical_files?.map(f => f.path) || [])}
  - All Patterns: ${JSON.stringify(contextPackage.exploration_results?.aggregated_insights?.all_patterns || [])}
  - All Integration Points: ${JSON.stringify(contextPackage.exploration_results?.aggregated_insights?.all_integration_points || [])}

  ## Analysis Steps

  ### 0. Load Output Schema (MANDATORY)
  Execute: cat ~/.ccw/workflows/cli-templates/schemas/conflict-resolution-schema.json

  ### 1. Load Context
  - Read existing files from conflict_detection.existing_files
  - Load plan from .workflow/active/${sessionId}/.process/context-package.json
  - Load exploration_results and use aggregated_insights for enhanced analysis
  - Extract role analyses and requirements

  ### 2. Execute CLI Analysis (Enhanced with Exploration + Scenario Uniqueness)

  Primary (Gemini):
  ccw cli -p "
  PURPOSE: Detect conflicts between plan and codebase, using exploration insights
  TASK:
  * Review pre-identified conflict_indicators from exploration results
  * Compare architectures (use exploration key_patterns)
  * Identify breaking API changes
  * Detect data model incompatibilities
  * Assess dependency conflicts
  * Analyze module scenario uniqueness
    - Use exploration integration_points for precise locations
    - Cross-validate with exploration critical_files
    - Generate clarification questions for boundary definition
  MODE: analysis
  CONTEXT: @**/*.ts @**/*.js @**/*.tsx @**/*.jsx @.workflow/active/${sessionId}/**/*
  EXPECTED: Conflict list with severity ratings, including:
    - Validation of exploration conflict_indicators
    - ModuleOverlap conflicts with overlap_analysis
    - Targeted clarification questions
  CONSTRAINTS: Focus on breaking changes, migration needs, and functional overlaps | Prioritize exploration-identified conflicts | analysis=READ-ONLY
  " --tool gemini --mode analysis --rule analysis-code-patterns --cd {project_root}

  Fallback: Qwen (same prompt) -> Claude (manual analysis)

  ### 3. Generate Strategies (2-4 per conflict)

  Template per conflict:
  - Severity: Critical/High/Medium
  - Category: Architecture/API/Data/Dependency/ModuleOverlap
  - Affected files + impact
  - For ModuleOverlap: Include overlap_analysis with existing modules and scenarios
  - Options with pros/cons, effort, risk
  - For ModuleOverlap strategies: Add clarification_needed questions for boundary definition
  - Recommended strategy + rationale

  ### 4. Return Structured Conflict Data

  Output to conflict-resolution.json (generated in Phase 4)

  **Schema Reference**: Execute cat ~/.ccw/workflows/cli-templates/schemas/conflict-resolution-schema.json to get full schema

  Return JSON following the schema. Key requirements:
  - Minimum 2 strategies per conflict, max 4
  - All text in Chinese for user-facing fields (brief, name, pros, cons, modification_suggestions)
  - modifications.old_content: 20-100 chars for unique Edit tool matching
  - modifications.new_content: preserves markdown formatting
  - modification_suggestions: 2-5 actionable suggestions for custom handling

  ### 5. Planning Notes Record (REQUIRED)
  After analysis complete, append to planning-notes.md:

  **File**: .workflow/active/${sessionId}/planning-notes.md
  **Location**: Under "## Conflict Decisions (Phase 3)" section
  **Format**:
  ### [Conflict-Resolution Agent] YYYY-MM-DD
  - **Note**: [Brief summary of conflict types, strategies, key decisions]
`)

Step 3.3: Iterative User Interaction

const autoYes = workflowPreferences?.autoYes || false;

FOR each conflict:
  round = 0, clarified = false, userClarifications = []

  WHILE (!clarified && round++ < 10):
    // 1. Display conflict info (text output for context)
    displayConflictSummary(conflict)  // id, brief, severity, overlap_analysis if ModuleOverlap

    // 2. Strategy selection
    if (autoYes) {
      console.log(`[autoYes] Auto-selecting recommended strategy`)
      selectedStrategy = conflict.strategies[conflict.recommended || 0]
      clarified = true  // Skip clarification loop
    } else {
      AskUserQuestion({
        questions: [{
          question: formatStrategiesForDisplay(conflict.strategies),
          header: "Strategy",
          multiSelect: false,
          options: [
            ...conflict.strategies.map((s, i) => ({
              label: `${s.name}${i === conflict.recommended ? ' (Recommended)' : ''}`,
              description: `${s.complexity} complexity | ${s.risk} risk${s.clarification_needed?.length ? ' | Needs clarification' : ''}`
            })),
            { label: "Custom modification", description: `Suggestions: ${conflict.modification_suggestions?.slice(0,2).join('; ')}` }
          ]
        }]
      })

      // 3. Handle selection
      if (userChoice === "Custom modification") {
        customConflicts.push({ id, brief, category, suggestions, overlap_analysis })
        break
      }

      selectedStrategy = findStrategyByName(userChoice)
    }

    // 4. Clarification (if needed) - batched max 4 per call
    if (!autoYes && selectedStrategy.clarification_needed?.length > 0) {
      for (batch of chunk(selectedStrategy.clarification_needed, 4)) {
        AskUserQuestion({
          questions: batch.map((q, i) => ({
            question: q, header: `Clarify${i+1}`, multiSelect: false,
            options: [{ label: "Provide details", description: "Enter answer" }]
          }))
        })
        userClarifications.push(...collectAnswers(batch))
      }

      // 5. Agent re-analysis
      reanalysisResult = Task({
        subagent_type: "cli-execution-agent",
        run_in_background: false,
        prompt: `Conflict: ${conflict.id}, Strategy: ${selectedStrategy.name}
User Clarifications: ${JSON.stringify(userClarifications)}
Output: { uniqueness_confirmed, rationale, updated_strategy, remaining_questions }`
      })

      if (reanalysisResult.uniqueness_confirmed) {
        selectedStrategy = { ...reanalysisResult.updated_strategy, clarifications: userClarifications }
        clarified = true
      } else {
        selectedStrategy.clarification_needed = reanalysisResult.remaining_questions
      }
    } else {
      clarified = true
    }

    if (clarified) resolvedConflicts.push({ conflict, strategy: selectedStrategy })
  END WHILE
END FOR

selectedStrategies = resolvedConflicts.map(r => ({
  conflict_id: r.conflict.id, strategy: r.strategy, clarifications: r.strategy.clarifications || []
}))

Step 3.4: Apply Modifications

// 1. Extract modifications from resolved strategies
const modifications = [];
selectedStrategies.forEach(item => {
  if (item.strategy && item.strategy.modifications) {
    modifications.push(...item.strategy.modifications.map(mod => ({
      ...mod,
      conflict_id: item.conflict_id,
      clarifications: item.clarifications
    })));
  }
});

console.log(`Applying ${modifications.length} modifications...`);

// 2. Apply each modification using Edit tool (with fallback to context-package.json)
const appliedModifications = [];
const failedModifications = [];
const fallbackConstraints = [];  // For files that don't exist

modifications.forEach((mod, idx) => {
  try {
    console.log(`[${idx + 1}/${modifications.length}] Modifying ${mod.file}...`);

    // Check if target file exists (brainstorm files may not exist in lite workflow)
    if (!file_exists(mod.file)) {
      console.log(`  File not found, writing to context-package.json as constraint`);
      fallbackConstraints.push({
        source: "conflict-resolution",
        conflict_id: mod.conflict_id,
        target_file: mod.file,
        section: mod.section,
        change_type: mod.change_type,
        content: mod.new_content,
        rationale: mod.rationale
      });
      return;  // Skip to next modification
    }

    if (mod.change_type === "update") {
      Edit({ file_path: mod.file, old_string: mod.old_content, new_string: mod.new_content });
    } else if (mod.change_type === "add") {
      const fileContent = Read(mod.file);
      const updated = insertContentAfterSection(fileContent, mod.section, mod.new_content);
      Write(mod.file, updated);
    } else if (mod.change_type === "remove") {
      Edit({ file_path: mod.file, old_string: mod.old_content, new_string: "" });
    }

    appliedModifications.push(mod);
    console.log(`  Success`);
  } catch (error) {
    console.log(`  Failed: ${error.message}`);
    failedModifications.push({ ...mod, error: error.message });
  }
});

// 3. Generate conflict-resolution.json output file
const resolutionOutput = {
  session_id: sessionId,
  resolved_at: new Date().toISOString(),
  summary: {
    total_conflicts: conflicts.length,
    resolved_with_strategy: selectedStrategies.length,
    custom_handling: customConflicts.length,
    fallback_constraints: fallbackConstraints.length
  },
  resolved_conflicts: selectedStrategies.map(s => ({
    conflict_id: s.conflict_id,
    strategy_name: s.strategy.name,
    strategy_approach: s.strategy.approach,
    clarifications: s.clarifications || [],
    modifications_applied: s.strategy.modifications?.filter(m =>
      appliedModifications.some(am => am.conflict_id === s.conflict_id)
    ) || []
  })),
  custom_conflicts: customConflicts.map(c => ({
    id: c.id, brief: c.brief, category: c.category,
    suggestions: c.suggestions, overlap_analysis: c.overlap_analysis || null
  })),
  planning_constraints: fallbackConstraints,
  failed_modifications: failedModifications
};

const resolutionPath = `.workflow/active/${sessionId}/.process/conflict-resolution.json`;
Write(resolutionPath, JSON.stringify(resolutionOutput, null, 2));

// 4. Update context-package.json with resolution details
const contextPkg = JSON.parse(Read(contextPath));
contextPkg.conflict_detection.conflict_risk = "resolved";
contextPkg.conflict_detection.resolution_file = resolutionPath;
contextPkg.conflict_detection.resolved_conflicts = selectedStrategies.map(s => s.conflict_id);
contextPkg.conflict_detection.custom_conflicts = customConflicts.map(c => c.id);
contextPkg.conflict_detection.resolved_at = new Date().toISOString();
Write(contextPath, JSON.stringify(contextPkg, null, 2));

// 5. Output custom conflict summary with overlap analysis (if any)
if (customConflicts.length > 0) {
  customConflicts.forEach(conflict => {
    console.log(`[${conflict.category}] ${conflict.id}: ${conflict.brief}`);
    if (conflict.category === 'ModuleOverlap' && conflict.overlap_analysis) {
      console.log(`Overlap info: New module: ${conflict.overlap_analysis.new_module.name}`);
    }
    conflict.suggestions.forEach(s => console.log(`  - ${s}`));
  });
}

TodoWrite Update (Phase 3 in progress, if conflict_risk >= medium)

[
  {"content": "Phase 1: Session Discovery", "status": "completed", "activeForm": "Executing session discovery"},
  {"content": "Phase 2: Context Gathering", "status": "completed", "activeForm": "Executing context gathering"},
  {"content": "Phase 3: Conflict Resolution", "status": "in_progress", "activeForm": "Resolving conflicts"},
  {"content": "  -> Detect conflicts with CLI analysis", "status": "in_progress", "activeForm": "Detecting conflicts"},
  {"content": "  -> Present conflicts to user", "status": "pending", "activeForm": "Presenting conflicts"},
  {"content": "  -> Apply resolution strategies", "status": "pending", "activeForm": "Applying resolution strategies"},
  {"content": "Phase 4: Task Generation", "status": "pending", "activeForm": "Executing task generation"}
]

TodoWrite Update (Phase 3 completed - tasks collapsed)

[
  {"content": "Phase 1: Session Discovery", "status": "completed", "activeForm": "Executing session discovery"},
  {"content": "Phase 2: Context Gathering", "status": "completed", "activeForm": "Executing context gathering"},
  {"content": "Phase 3: Conflict Resolution", "status": "completed", "activeForm": "Resolving conflicts"},
  {"content": "Phase 4: Task Generation", "status": "pending", "activeForm": "Executing task generation"}
]

Step 3.5: Update Planning Notes

After conflict resolution completes (if executed), update planning-notes.md:

if (conflictRisk === 'medium' || conflictRisk === 'high') {
  const conflictResPath = `.workflow/active/${sessionId}/.process/conflict-resolution.json`;

  if (file_exists(conflictResPath)) {
    const conflictRes = JSON.parse(Read(conflictResPath));
    const resolved = conflictRes.resolved_conflicts || [];
    const modifiedArtifacts = conflictRes.modified_artifacts || [];
    const planningConstraints = conflictRes.planning_constraints || [];

    // Update Phase 3 section
    Edit(planningNotesPath, {
      old: '## Conflict Decisions (Phase 3)\n(To be filled if conflicts detected)',
      new: `## Conflict Decisions (Phase 3)

- **RESOLVED**: ${resolved.map(r => `${r.type} -> ${r.strategy}`).join('; ') || 'None'}
- **MODIFIED_ARTIFACTS**: ${modifiedArtifacts.join(', ') || 'None'}
- **CONSTRAINTS**: ${planningConstraints.join('; ') || 'None'}`
    })

    // Append Phase 3 constraints to consolidated list
    if (planningConstraints.length > 0) {
      const currentNotes = Read(planningNotesPath);
      const constraintCount = (currentNotes.match(/^\d+\./gm) || []).length;

      Edit(planningNotesPath, {
        old: '## Consolidated Constraints (Phase 4 Input)',
        new: `## Consolidated Constraints (Phase 4 Input)
${planningConstraints.map((c, i) => `${constraintCount + i + 1}. [Conflict] ${c}`).join('\n')}`
      })
    }
  }
}

Auto-Continue: Return to user showing conflict resolution results and selected strategies, then auto-continue.

Auto Mode: When workflowPreferences.autoYes is true, conflict-resolution automatically applies recommended resolution strategies without user confirmation.

Step 3.6: Memory State Check

Evaluate current context window usage and memory state:

  • If memory usage is high (>120K tokens or approaching context limits):
Skill(skill="memory-capture")
  • Memory compaction is particularly important after analysis phase which may generate extensive documentation
  • Ensures optimal performance and prevents context overflow

Output

  • File: conflict-resolution.json (if conflicts resolved)
  • TodoWrite: Mark Phase 3 completed, Phase 4 in_progress

Next Phase

Return to orchestrator, then auto-continue to Phase 4: Task Generation.