# ohos-sdk-code-review §4.1 优化 — 变更总结

> 配套设计文档：`hybrid-code-scan-design.md`
> 落地日期：2026-06-15 | 实测环境：macOS + DevEco Studio（CodeLinter 6.0.240）
> 状态：已实现并端到端实测通过；Windows 实机回归待办

把 SKILL.md §4.1「CodeArts Check 强制扫描」从 **~45 条 grep** 改为**一次工具调用**的混合架构扫描（CodeLinter + 轻量扫描器）。模型只发起 1 次调用，得到结构化 / 去重 / 分级 / 魔法值归并 / 逐组日志的统一结果，机械类问题直接据此修复，把时间花在「修」而非「过滤 grep 噪声」。

---

## 一、改了哪些文件

| 文件 | 状态 | 说明 |
|---|---|---|
| `ohos-sdk-code-review/SKILL.md` | **已跟踪·改** | §4.1 改写为「调用统一工具 + 处理结果」 |
| `scripts/review-scan.cjs` | **新增·可入库** | 统一入口：编排 Layer1+2、合并/去重、写日志、退出码 |
| `scripts/codelinter-adapter.cjs` | 新增·可入库 | CodeLinter 发现 / 版本 / 完整性自检(缓存) / 运行解析 |
| `scripts/custom-scanner.cjs` | 新增·可入库 | tokenize + 27 条规则（盲区 + 兜底） |
| `scripts/rule-manifest.json` | 新增·可入库 | 单一事实源：cr-* ↔ G.xxx ↔ CodeLinter 规则 ↔ scanner ↔ fixture |
| `scripts/code-linter.review.json5` | 新增·可入库 | 审查专用 CodeLinter 配置 |
| `scripts/README.md` | 新增·可入库 | 用法 / 约束 / 维护 |
| `docs/hybrid-code-scan-design.md` | 新增·**不入库** | 完整设计文档 |
| `docs/change-summary.md` | 新增·**不入库** | 本文档 |

> 仓库根 `.gitignore` 全局忽略 `tools/` 和 `docs/`。故工具放 `scripts/`（可入库，且是本仓既有先例），设计/总结文档留在 `docs/`（按既定选择不入库）。`SKILL.md` + `scripts/` 会随 `git add` 一起入库，clone 后不断链。

---

## 二、核心要点

1. **§4.1 从 ~45 条 grep → 1 次工具调用**；输出结构化、去重、分级、魔法值归并、逐组日志（自动写 `code-review.log`，杜绝「scanning completed」一句话糊弄）。
2. **混合架构**：CodeLinter（华为本地引擎，权威）+ 轻量扫描器（盲区补充 + 兜底）；两层输出同一 JSON 契约，模型不感知底层引擎。
3. **完整性自检**：用 fixture 在运行时**实测**每条规则是否真生效，决定 codelinter/custom 路由——因为实测发现「配了规则 ≠ 会执行」。
4. **跨平台**：Windows / macOS 同一条 `node …/review-scan.cjs` 命令，OS 差异全在 wrapper 内吸收。
5. **`--apply-fix` 默认开**：自动修纯格式规则并**可审计**（`status: auto_fixed`、计入 `issues_fixed`），`--no-apply-fix` 关闭。

---

## 三、实现原理

### 入口 `review-scan.cjs` 流程

解析参数 / 校验工程根 → 收集变更文件（过滤 test/oh_modules/build）→ 可用性探测 → 完整性自检得覆盖矩阵 → 决定 mode（FULL_CODELINTER / HYBRID_PARTIAL / DEGRADED_CUSTOM）→ 跑 Layer1 + Layer2 → 合并 / 去重 / 魔法值聚合 / 写日志 → 输出 JSON + 退出码。

### Layer 1：CodeLinter

- **发现**：env 覆盖（`OHOS_CODELINTER_JS` / `DEVECO_HOME`）→ 各平台 DevEco 默认安装路径 → 由 PATH 上的 `hvigorw`/`ohpm` 反推 DevEco 根。node 用 `process.execPath`。
- **自检**：把 manifest 各 codelinter 规则的 fixture 合成一个文件，写到**被审查文件所在目录**（必在源码根、非点目录）跑一遍，看哪些规则真触发 → 覆盖矩阵；结果按 `版本 + 配置 + manifest` 哈希**缓存**于 `<project>/.ohos-adaptation/logs/.codelinter-cache/`。
- **运行**：`node run/index.js -c <配置> -f json -o <报告> <文件…>`，解析 JSON，按 manifest 把 `@rule` 映回 `cr-*` / P0–P3。
- **自动修**（默认开）：先出「修复前基线」报告 → 跑 `--fix`（改写文件，其输出即「修复后剩余」）→ 差集（基线有、修复后无）= 被修项，记 `status: auto_fixed`，`summary.auto_fixed` 计数。

### Layer 2：轻量扫描器

- 先 `maskCode`：把注释、字符串/模板的**内容**替换为空格（保留行列/引号）→ 在纯代码上跑规则，消灭「字符串/注释里的数字、`== null`」等正则误报。
- 安全类（md5/密钥/日志）信号在字符串里，改走 raw 行；Android 残留 import 因包名在被 mask 的模块串里，也走 raw。
- 职责：永久负责 CodeLinter 不实现的（Android 残留 P0、JSON.parse、文件流、密钥/日志…）；DEGRADED 或某规则自检失败时兜底全部机械规则。

### 路由

每条规则按「可用性 + 覆盖矩阵 + manifest.engine」决定归 codelinter 还是 custom；codelinter 运行出错则其规则自动降级给 custom（mode 转 HYBRID_PARTIAL）。

---

## 四、统一输出契约（关键字段）

- `engine.mode`：`FULL_CODELINTER` / `HYBRID_PARTIAL` / `DEGRADED_CUSTOM`。
- `engine.coverage.by_rule`：每条规则实际由 `codelinter` 还是 `custom` 负责（自检得出）。
- `findings[]`：`rule`(cr-*)、`g_id`、`severity`(P0–P3)、`file`、`line`、`snippet`、`confidence`(`confirmed`/`needs_review`)、`status`(`open`/`auto_fixed`)。
- `magic_values[]`：按值去重的魔法值清单（值 + 全部用法点 sites + 占位常量名）。
- `summary`：`p0..p3` = **剩余**(open) 计数；`auto_fixed` = 已自动修复计数；`issues_found` = 总数。
- `log_lines[]`：逐规则命中记录（含「无命中」）。
- **退出码**：`0`=无剩余 P0/P1；`10`=有剩余 P0/P1（门禁阻断）；`20`=工具自身错误。

---

## 五、实测验证

| 场景 | 结果 |
|---|---|
| HYBRID（有 DevEco） | CodeLinter + 自定义分工；`@typescript-eslint/{quotes,array-type,…}` 由 CodeLinter，Android 残留/`===`/魔法值/命名等由自定义 |
| DEGRADED（`--no-codelinter`） | 全部自定义兜底，命中数与 HYBRID 一致 |
| 干净文件 | 0 命中、0 误报，exit 0 |
| 默认自动修 | `auto_fixed` 计数正确，被修项记 `status:auto_fixed` 并从 open 移出，文件被改写 |
| `--no-apply-fix` | 文件不动，`auto_fixed=0` |
| 自检缓存 | 第二次 `from_cache: true` |
| 按 SKILL.md 命令原样跑 | 通过，`code-review.log` 正确写入 |

---

## 六、注意事项

1. **CodeLinter 不在 PATH**，藏在 DevEco `plugins/codelinter/run/index.js`（路径含版本号）；CI / 无 DevEco 机器用 `OHOS_CODELINTER_JS` / `DEVECO_HOME` 指定，否则进 DEGRADED。
2. **配了规则 ≠ 会执行**：实测 CodeLinter 只稳定跑 `eqeqeq` + `@typescript-eslint/{quotes,array-type,no-magic-numbers,no-array-constructor,naming-convention,keyword-spacing}` + `@security/*`，其余（use-isnan/no-unsafe-finally/curly/dot-notation/prefer-for-of/one-var/max-len 等）配了也不跑，全靠自检兜底——**别假设**某规则一定被 CodeLinter 覆盖。
3. CodeLinter **只扫模块源码根内、非点开头目录**的文件（自检 fixture 因此放 `__review_selfcheck__/` 并即时清理）。
4. **`--apply-fix` 默认会改写工作树**（仅纯格式、不改语义）；目标文件若已 assembleHar/Hap，自动修复后建议复编一次确认；DEGRADED 下自动修复不生效。
5. **门禁**：退出码只看**剩余** open P0/P1；`auto_fixed` 须计入产物 `review_summary.issues_fixed`，保证可审计、不静默改码。
6. **魔法值口径**已对齐 CodeLinter（忽略 `0`/`1`/`-1` 与数组下标），比旧 SKILL「所有字面量不豁免」宽松——有意为之，减少无谓改动；语义关键的 0/1 由模型在阅读阶段按需补。
7. **未替代语义审查**：假实现、资源对称释放、公开 API 导出契约仍须模型阅读（`references/ets-review-rules.md`）。
8. **待办**：Windows 路径与规则覆盖需在 Windows + DevEco 实机回归（设计文档 §19）；可选把 `auto_fixed` 接入 `03-code-review.json` 产物字段的自动填充。

---

## 七、维护指引

- 新增/调整规则：改 `scripts/rule-manifest.json`（codelinter 规则带 `fixture` + `expect_rule`；custom 规则在 `custom-scanner.cjs` 的 `SCANNERS` 加同名函数）。
- 改 `engine_rule`/`fixture`/配置后，自检缓存键变化会自动重跑，无需手动清缓存。
- 详见 `scripts/README.md` 与 `docs/hybrid-code-scan-design.md`。
