# Command: semantic-scan > LLM-based semantic analysis via CLI. Supplements toolchain findings with issues that static tools cannot detect: business logic flaws, architectural problems, complex security patterns. ## When to Use - Phase 3 of Scanner, Standard mode, Step B - Runs AFTER toolchain-scan completes (needs its output to avoid duplication) - Quick mode does NOT use this command **Trigger conditions**: - SCAN-* task in Phase 3 with `quickMode === false` - toolchain-scan.md has completed (toolchain-findings.json exists or empty) ## Strategy ### Delegation Mode **Mode**: CLI Fan-out (single gemini agent, analysis only) ### Tool Fallback Chain ``` gemini (primary) -> qwen (fallback) -> codex (fallback) ``` ## Execution Steps ### Step 1: Prepare Context Build the CLI prompt with target files and a summary of toolchain findings to avoid duplication. ```javascript // Read toolchain findings for dedup context let toolFindings = [] try { toolFindings = JSON.parse(Read(`${sessionFolder}/scan/toolchain-findings.json`)) } catch { /* no toolchain findings */ } // Build toolchain summary for dedup (compact: file:line:rule per line) const toolSummary = toolFindings.length > 0 ? toolFindings.slice(0, 50).map(f => `${f.location?.file}:${f.location?.line} [${f.source}] ${f.title}` ).join('\n') : '(no toolchain findings)' // Build target file list for CLI context // Limit to reasonable size for CLI prompt const fileList = targetFiles.slice(0, 100) const targetPattern = fileList.length <= 20 ? fileList.join(' ') : `${target}/**/*.{ts,tsx,js,jsx,py,go,java,rs}` // Map requested dimensions to scan focus areas const DIM_FOCUS = { sec: 'Security: business logic vulnerabilities, privilege escalation, sensitive data flow, auth bypass, injection beyond simple patterns', cor: 'Correctness: logic errors, unhandled exception paths, state management bugs, race conditions, incorrect algorithm implementation', perf: 'Performance: algorithm complexity (O(n^2)+), N+1 queries, unnecessary sync operations, memory leaks, missing caching opportunities', maint: 'Maintainability: architectural coupling, abstraction leaks, project convention violations, dead code paths, excessive complexity' } const focusAreas = dimensions .map(d => DIM_FOCUS[d]) .filter(Boolean) .map((desc, i) => `${i + 1}. ${desc}`) .join('\n') ``` ### Step 2: Execute CLI Scan ```javascript const maxPerDimension = 5 const minSeverity = 'medium' const cliPrompt = `PURPOSE: Supplement toolchain scan with semantic analysis that static tools cannot detect. Find logic errors, architectural issues, and complex vulnerability patterns. TASK: ${focusAreas} MODE: analysis CONTEXT: @${targetPattern} Toolchain already detected these issues (DO NOT repeat them): ${toolSummary} EXPECTED: Respond with ONLY a JSON array (no markdown, no explanation). Each element: {"dimension":"security|correctness|performance|maintainability","category":"","severity":"critical|high|medium","title":"","description":"","location":{"file":"","line":,"end_line":,"code_snippet":""},"source":"llm","suggested_fix":"","effort":"low|medium|high","confidence":"high|medium|low"} CONSTRAINTS: Max ${maxPerDimension} findings per dimension | Only ${minSeverity} severity and above | Do not duplicate toolchain findings | Focus on issues tools CANNOT detect | Return raw JSON array only` let cliOutput = null let cliTool = 'gemini' // Try primary tool try { cliOutput = Bash( `ccw cli -p "${cliPrompt.replace(/"/g, '\\"')}" --tool gemini --mode analysis --rule analysis-review-code-quality`, { timeout: 300000 } ) } catch { // Fallback to qwen try { cliTool = 'qwen' cliOutput = Bash( `ccw cli -p "${cliPrompt.replace(/"/g, '\\"')}" --tool qwen --mode analysis`, { timeout: 300000 } ) } catch { // Fallback to codex try { cliTool = 'codex' cliOutput = Bash( `ccw cli -p "${cliPrompt.replace(/"/g, '\\"')}" --tool codex --mode analysis`, { timeout: 300000 } ) } catch { // All CLI tools failed cliOutput = null } } } ``` ### Step 3: Parse & Validate Output ```javascript let semanticFindings = [] if (cliOutput) { try { // Extract JSON array from CLI output (may have surrounding text) const jsonMatch = cliOutput.match(/\[[\s\S]*\]/) if (jsonMatch) { const parsed = JSON.parse(jsonMatch[0]) // Validate each finding against schema semanticFindings = parsed.filter(f => { // Required fields check if (!f.dimension || !f.title || !f.location?.file) return false // Dimension must be valid if (!['security', 'correctness', 'performance', 'maintainability'].includes(f.dimension)) return false // Severity must be valid and meet minimum const validSev = ['critical', 'high', 'medium'] if (!validSev.includes(f.severity)) return false return true }).map(f => ({ dimension: f.dimension, category: f.category || 'general', severity: f.severity, title: f.title, description: f.description || f.title, location: { file: f.location.file, line: f.location.line || 1, end_line: f.location.end_line || f.location.line || 1, code_snippet: f.location.code_snippet || '' }, source: 'llm', tool_rule: null, suggested_fix: f.suggested_fix || '', effort: ['low', 'medium', 'high'].includes(f.effort) ? f.effort : 'medium', confidence: ['high', 'medium', 'low'].includes(f.confidence) ? f.confidence : 'medium' })) } } catch { // JSON parse failed - log and continue with empty } } // Enforce per-dimension limits const dimCounts = {} semanticFindings = semanticFindings.filter(f => { dimCounts[f.dimension] = (dimCounts[f.dimension] || 0) + 1 return dimCounts[f.dimension] <= maxPerDimension }) // Write output Write(`${sessionFolder}/scan/semantic-findings.json`, JSON.stringify(semanticFindings, null, 2)) ``` ## Error Handling | Scenario | Resolution | |----------|------------| | gemini CLI fails | Fallback to qwen, then codex | | All CLI tools fail | Log warning, write empty findings array (toolchain results still valid) | | CLI output not valid JSON | Attempt regex extraction, else empty findings | | Findings exceed per-dimension limit | Truncate to max per dimension | | Invalid dimension/severity in output | Filter out invalid entries | | CLI timeout (>5 min) | Kill, log warning, return empty findings |