# Action: Deep Review

深入审查指定维度的代码质量。

## Purpose

针对单个维度进行深入审查：
- 逐文件检查
- 记录发现的问题
- 提供具体的修复建议

## Preconditions

- [ ] state.status === 'running'
- [ ] state.scan_completed === true
- [ ] 存在未审查的维度

## Dimension Focus Areas

### Correctness (正确性)
- 逻辑错误和边界条件
- Null/undefined 处理
- 错误处理完整性
- 类型安全
- 资源泄漏

### Readability (可读性)
- 命名规范
- 函数长度和复杂度
- 代码重复
- 注释质量
- 代码组织

### Performance (性能)
- 算法复杂度
- 不必要的计算
- 内存使用
- I/O 效率
- 缓存策略

### Security (安全性)
- 注入风险 (SQL, XSS, Command)
- 认证和授权
- 敏感数据处理
- 加密使用
- 依赖安全

### Testing (测试)
- 测试覆盖率
- 边界条件测试
- 错误路径测试
- 测试可维护性
- Mock 使用

### Architecture (架构)
- 分层结构
- 依赖方向
- 单一职责
- 接口设计
- 扩展性

## Execution

```javascript
async function execute(state, workDir, currentDimension) {
  const context = state.context;
  const dimension = currentDimension;
  const findings = [];

  // 从外部 JSON 文件加载规则
  const rulesConfig = loadRulesConfig(dimension, workDir);
  const rules = rulesConfig.rules || [];
  const prefix = rulesConfig.prefix || getDimensionPrefix(dimension);

  // 优先审查高风险区域
  const filesToReview = state.scan_summary?.risk_areas
    ?.map(r => r.file)
    ?.filter(f => context.files.includes(f)) || context.files;

  const filesToCheck = [...new Set([
    ...filesToReview.slice(0, 20),
    ...context.files.slice(0, 30)
  ])].slice(0, 50);  // 最多50个文件

  let findingCounter = 1;

  for (const file of filesToCheck) {
    try {
      const content = Read(file);
      const lines = content.split('\n');

      // 应用外部规则文件中的规则
      for (const rule of rules) {
        const matches = detectByPattern(content, lines, file, rule);
        for (const match of matches) {
          findings.push({
            id: `${prefix}-${String(findingCounter++).padStart(3, '0')}`,
            severity: rule.severity || match.severity,
            dimension: dimension,
            category: rule.category,
            file: file,
            line: match.line,
            code_snippet: match.snippet,
            description: rule.description,
            recommendation: rule.recommendation,
            fix_example: rule.fixExample
          });
        }
      }
    } catch (e) {
      // 跳过无法读取的文件
    }
  }

  // 保存维度发现
  Write(`${workDir}/findings/${dimension}.json`, JSON.stringify(findings, null, 2));

  return {
    stateUpdates: {
      reviewed_dimensions: [...(state.reviewed_dimensions || []), dimension],
      current_dimension: null,
      [`findings.${dimension}`]: findings
    }
  };
}

/**
 * 从外部 JSON 文件加载规则配置
 * 规则文件位于 specs/rules/{dimension}-rules.json
 * @param {string} dimension - 维度名称 (correctness, security, etc.)
 * @param {string} workDir - 工作目录 (用于日志记录)
 * @returns {object} 规则配置对象，包含 rules 数组和 prefix
 */
function loadRulesConfig(dimension, workDir) {
  // 规则文件路径：相对于 skill 目录
  const rulesPath = `specs/rules/${dimension}-rules.json`;

  try {
    const rulesFile = Read(rulesPath);
    const rulesConfig = JSON.parse(rulesFile);
    return rulesConfig;
  } catch (e) {
    console.warn(`Failed to load rules for ${dimension}: ${e.message}`);
    // 返回空规则配置，保持向后兼容
    return { rules: [], prefix: getDimensionPrefix(dimension) };
  }
}

/**
 * 根据规则的 patternType 检测代码问题
 * 支持的 patternType: regex, includes
 * @param {string} content - 文件内容
 * @param {string[]} lines - 按行分割的内容
 * @param {string} file - 文件路径
 * @param {object} rule - 规则配置对象
 * @returns {Array} 匹配结果数组
 */
function detectByPattern(content, lines, file, rule) {
  const matches = [];
  const { pattern, patternType, negativePatterns, caseInsensitive } = rule;

  if (!pattern) return matches;

  switch (patternType) {
    case 'regex':
      return detectByRegex(content, lines, pattern, negativePatterns, caseInsensitive);

    case 'includes':
      return detectByIncludes(content, lines, pattern, negativePatterns);

    default:
      // 默认使用 includes 模式
      return detectByIncludes(content, lines, pattern, negativePatterns);
  }
}

/**
 * 使用正则表达式检测代码问题
 * @param {string} content - 文件完整内容
 * @param {string[]} lines - 按行分割的内容
 * @param {string} pattern - 正则表达式模式
 * @param {string[]} negativePatterns - 排除模式列表
 * @param {boolean} caseInsensitive - 是否忽略大小写
 * @returns {Array} 匹配结果数组
 */
function detectByRegex(content, lines, pattern, negativePatterns, caseInsensitive) {
  const matches = [];
  const flags = caseInsensitive ? 'gi' : 'g';

  try {
    const regex = new RegExp(pattern, flags);
    let match;

    while ((match = regex.exec(content)) !== null) {
      const lineNum = content.substring(0, match.index).split('\n').length;
      const lineContent = lines[lineNum - 1] || '';

      // 检查排除模式 - 如果行内容匹配任一排除模式则跳过
      if (negativePatterns && negativePatterns.length > 0) {
        const shouldExclude = negativePatterns.some(np => {
          try {
            return new RegExp(np).test(lineContent);
          } catch {
            return lineContent.includes(np);
          }
        });
        if (shouldExclude) continue;
      }

      matches.push({
        line: lineNum,
        snippet: lineContent.trim().substring(0, 100),
        matchedText: match[0]
      });
    }
  } catch (e) {
    console.warn(`Invalid regex pattern: ${pattern}`);
  }

  return matches;
}

/**
 * 使用字符串包含检测代码问题
 * @param {string} content - 文件完整内容 (未使用但保持接口一致)
 * @param {string[]} lines - 按行分割的内容
 * @param {string} pattern - 要查找的字符串
 * @param {string[]} negativePatterns - 排除模式列表
 * @returns {Array} 匹配结果数组
 */
function detectByIncludes(content, lines, pattern, negativePatterns) {
  const matches = [];

  lines.forEach((line, i) => {
    if (line.includes(pattern)) {
      // 检查排除模式 - 如果行内容包含任一排除字符串则跳过
      if (negativePatterns && negativePatterns.length > 0) {
        const shouldExclude = negativePatterns.some(np => line.includes(np));
        if (shouldExclude) return;
      }

      matches.push({
        line: i + 1,
        snippet: line.trim().substring(0, 100),
        matchedText: pattern
      });
    }
  });

  return matches;
}

/**
 * 获取维度前缀（作为规则文件不存在时的备用）
 * @param {string} dimension - 维度名称
 * @returns {string} 4字符前缀
 */
function getDimensionPrefix(dimension) {
  const prefixes = {
    correctness: 'CORR',
    readability: 'READ',
    performance: 'PERF',
    security: 'SEC',
    testing: 'TEST',
    architecture: 'ARCH'
  };
  return prefixes[dimension] || 'MISC';
}
```

## State Updates

```javascript
return {
  stateUpdates: {
    reviewed_dimensions: [...state.reviewed_dimensions, currentDimension],
    current_dimension: null,
    findings: {
      ...state.findings,
      [currentDimension]: newFindings
    }
  }
};
```

## Output

- **File**: `findings/{dimension}.json`
- **Location**: `${workDir}/findings/`
- **Format**: JSON array of Finding objects

## Error Handling

| Error Type | Recovery |
|------------|----------|
| 文件读取失败 | 跳过该文件，记录警告 |
| 规则执行错误 | 跳过该规则，继续其他规则 |

## Next Actions

- 还有未审查维度: 继续 action-deep-review
- 所有维度完成: action-generate-report
