Files

12 KiB
Raw Permalink Blame History

并行深读流水线(Step 5.5 操作手册)

目的:让 whole-project 审查达到全库覆盖 ≥85% 且高风险 ≥95%(双目标 gate="both",文件数口径)每个深读文件通过三件套质量门禁(单元完整性 / 行覆盖 / 防伪抽验)。 核心:主上下文不逐文件深读,改用并行 explore 子代理分组深读,每个子代理返回 「深读确认清单 + semantic_units + read_ranges + findings(带 file:line 证据)」,结果落盘给聚合脚本校验。

〇、三件套质量门禁(V2.1,每个深读文件必须通过)

# 门禁 定义 阈值 角色 防伪性
单元完整性 semantic_units 与图谱单元节点差集 = 空 100%(硬) 防漏读(跳过后半段) 引擎/脚本自动核验
行覆盖 union(read_ranges) / 真实行数 ≥95% 防"每单元只读一行" 低(自报粒度)
防伪抽验 主代理回读抽样单元 每组 2 文件 × 2-3 单元/文件,每波 ≤40 次 防假读(抄清单不读) 唯一防假读手段

判定规则:

  • ① 单元被覆盖 = 图谱单元 [ls,le] 与上报 semantic_units 中某 range 精确匹配(优先)或重叠 ≥80%(兜底),且该单元 ≥80% 行落在 union(read_ranges) 内;一个上报 range 只能匹配一个单元(one-to-one),宽 range 无法覆盖多个单元。
  • 巨型文件豁免 ①:单元数<3最大单元行占比>80%(如 migrations.rs run_migrations 6200/6331=98%)→ 该文件仅按 ② 行覆盖校验,引擎/脚本返回 unit_exempt_files
  • ② 分母 = 真实文件行数(读取源文件,非图节点 line_end——已验证 ±1 偏差),行数缓存。
  • ③ 预算:每波 ≤40 次 read(每波 4-6 组 × 2 文件 × 3 单元 ≈ 24-36,留余量);每组抽 2 文件、每文件抽 2-3 单元回读比对 note;抽到假读 → 该组重读并升级抽验率。结果必须落盘 spot_check_<batch>.json 并在 Step 8 聚合注入 review_data.spot_check(顶层字段),否则报告渲染"防伪抽验:未执行 🔴"且 verify-spot-check.ps1 exit 1。

诚实声明:引擎无法防假读。① 防漏单元、② 防读不全、③(抽样)才是唯一防假读的手段,且为预算化而非全量。verify-spot-check.ps1 只能验证抽验声明完整性(抽了、单元数>0、range 落在 read_ranges 内),无法验证主代理是否真读了文件。

一、分组规则

以 AuraSpace 实测分组表为基准(约 508 源文件 → 14-16 组,每组 ≤40 文件):

# 组(目录) 约文件数 子代理职责
1 server/src/api1/2 30 后端 API 层前半
2 server/src/api2/2 31 后端 API 层后半
3 server/src/services1/2 33 核心业务服务前半
4 server/src/services2/2 33 核心业务服务后半
5 server/src/domain 43 领域模型/DTO
6 server/src/deepwiki + infrastructure 25 DeepWiki + 基础设施
7 server/tests + bin + models 14 测试与工具二进制
8 web/src/views1/2 34 前端视图前半
9 web/src/views2/2 33 前端视图后半
10 web/src/components1/3 38 前端组件(issues/evm/ci
11 web/src/components2/3 38 前端组件(docs/wiki/time-log/settings
12 web/src/components3/3 37 前端组件(ppt/agent/opencode/common/ui
13 web/src/store + utils + api 31 状态管理/工具函数/API 客户端
14 web/src/hooks + services + generated + web/tests 前端其余(可分 2 组)

实际以 deep_read_plan_tool(gate="overall", target_coverage=85, include_prior=True) 返回的 groups 为准(引擎按风险权重贪心 + 目录分组,数量随仓库变化)。 每次并行派发 4-6 个子代理,其余排队分批,避免 MCP 并发压力与上下文风暴。

二、子代理 Prompt 模板(V2.1,含三件套协议)

对每个组派发如下 prompt(替换 <GROUP> / <FILE_LIST> / <输出目录> / <临时输出文件>):

你是一个代码审查深读子代理。请深读以下 <GROUP> 组的全部文件:

<FILE_LIST(每行一个相对路径)>

要求:
1. 逐文件用 read 读取完整内容(文件大则分段读),**不要跳过任何文件**。
2. 对每个文件,从八个类别审视:interface / business / data / utility /
   error handling / security / performance / observability,并叠加
   CRITICAL 子轮:SQL 与数据安全、竞态条件、LLM 输出信任边界、Shell 注入、枚举完备性。
3. 只报告**真实问题**(严重度 blocker/major/minor,置信度 1-10)。
   每条 finding 必须含 file:line 证据(实际读取到的行),没有证据视为未深读。
4. 良好实践、无问题的文件,在 deep_read 确认清单中标注,不产出 finding。
5. **每个文件必须填写质量字段**(这是硬性要求,缺失视为未深读):
   - total_lines: 文件真实总行数(从 read 输出得知)
   - read_ranges: 实际读取的行区间数组 [[s,e],...](分段读即天然区间),
     闭区间,并集应覆盖你读过的每一行
   - semantic_units: 你实际读过的每个语义单元(函数/类/接口)摘要,
     {"range":[s,e],"kind":"Function|Class|Test","name":"<符号名>","note":"<≤60字摘要>"}
     **严格模式(强制)**:必须**逐一列出该文件图谱中的全部语义单元**,
     包括:
     - 所有 Function(含私有/辅助小函数)
     - 所有 Class / interface / Type(含 Props 接口、仅数行的小接口——如
       `MermaidBlockProps`3 行)、`NavEntry`5 行)也必须单独列出)
     - 不得把 Props interface / 小接口并入父组件或跳过
     - 一个语义单元 = 一个 semantic_units 条目,range 取该符号的实际
       [line_start, line_end]
     跳过任一图谱单元 = 漏读,会被单元完整性差集校验检出(unit_gap)→ 该文件须补报重读

输出(结构化,仅此格式),写入 <临时输出文件>(JSON 文件,不要回传大文本):
{
  "group": "<GROUP>",
  "outputs": [
    {
      "path": "相对路径",
      "total_lines": <int>,
      "read_ranges": [[s,e], ...],
      "semantic_units": [{"range":[s,e],"kind":"...","name":"...","note":"..."}],
      "findings": [
        {"path": "...", "line": <int>, "severity": "blocker|major|minor",
         "category": "security|business|data|...", "confidence": <1-10>,
         "message": "问题描述(含具体行内容证据)", "fix": "修复建议"}
      ]
    }
  ],
  "summary": "本组一句话结论(主要风险点)"
}

深读确认 = 该组文件全部出现在 outputs 中,且每个都有 total_lines/read_ranges/semantic_units

禁止退化格式:不得把子代理输出简化为 DEEPREAD_CONFIRM: <路径|总行数|已读范围|单元数> 单行文本。 那会使主代理拿不到分段 read_ranges 与逐单元 semantic_units,导致 coverage_tool 三件套门禁 无法执行、报告"无行覆盖"。子代理 prompt 必须使用本节模板原样复制。

三、输出 Schema(子代理 → 落盘 → 主代理)

  • 落盘机制(强制):子代理把上述 JSON 写入主代理指定的临时目录(如 C:\Users\ADMINI~1\AppData\Local\Temp\opencode\review\batchN.json)。 不要把 1-2MB JSON 回传主上下文——主代理只读聚合结果摘要。
  • 每波子代理完成后,主代理运行聚合脚本:
    python skills/project-review/scripts/aggregate_deep_read.py <repo_root> <输出目录>
    
    返回 verified_files / line_gap_files / unit_gap_files / unit_exempt_files / summary

四、主代理收尾流程

1. 每波子代理完成后(不等全部结束):
   aggregate_deep_read.py <repo_root> <落盘目录>
2. 汇总三件套判定:
   - line_gap_files  unit_gap_files → 补读队列(下波派发,禁止跳过)
   - unit_exempt_files → 仅按行覆盖校验(已由脚本处理)
   - verified_files → 计入本轮 deep_read_files
3. 防伪抽验(**强制,每波必做**):对每组抽 **2 文件**、每文件抽 2-3 个语义单元,
   回读源文件对应行比对 semantic_units.note。每波 ≤40 次 read。抽到假读 → 该组重读并升级抽验率。
   结果落盘 `spot_check_<batch>.json`schemagroups_sampled / files_sampled / units_sampled /
   fake_read_found / groups_rereread / samples[{group,file,unit,range,note_match,in_read_ranges}])。
4. 全部达标后,三件套数据传入引擎 coverage_toolB 阶段引擎原生支持):
   coverage_tool(deep_read_files=<verified_files>, gate="both+line",
                 file_read_ranges=<{rel:[[s,e]..]}>, file_semantic_units=<{rel:[...]}>)
   → 引擎返回 line_coverage_pct / unit_coverage_pct / line_gap_files / unit_gap_files / unit_exempt_files
   ⚠️ 禁止降级:unit_gap_files 或 line_gap_files 非空时,**不得**改回 gate="both" 静默跳过;
     必须补轮重读至空,或在报告中显式标注"三件套未达标 🔴"并列出缺口文件。
5. 未达标(文件数 <85%/<95% 或行覆盖 <95% 或单元有缺口)→
   按 priority_deep_read_files / line_gap_files / unit_gap_files 补一轮(可再派 1-3 个子代理)。
6. G2:对 silent_files 随机抽 15% 深读(本轮未覆盖的静默文件)。
7. 报告生成前:聚合全部 `spot_check_*.json` → 注入 `review_data.spot_check`(顶层字段)。
8. G3:三件套 + 文件数双口径达标 → 报告生成(覆盖度区块须含行/单元覆盖 + 防伪抽验)→
   跑 verify-spot-check.ps1Step 8.8)→ save_coverage_index_tool(deep_read_files=<verified_files>, file_read_ranges=<ranges>) 写 v2 索引。

五、质量控制与防伪

风险 对策
子代理"声称读了"但没真读 强制 total_lines/read_ranges/semantic_units 三字段 + findings 带行号;聚合脚本按①差集+②行并集双校验;主代理③抽样回读
子代理漏读文件 outputs 与分组清单 diff,漏读计入覆盖率缺口,触发补轮
子代理宽 range 冒充全读 ① one-to-one 匹配:一个上报 range 只能覆盖一个单元,无法用整文件 range 覆盖所有单元
子代理漏报小单元(Props interface / Type / 小函数) 严格模式:semantic_units 必须逐一列出图谱全部单元(含 3-5 行的小接口);unit_gap 非空 → 该文件补报重读,不得视为已深读
子代理各自为政口径不一 统一八类 + CRITICAL 子轮 + severity/confidence 标准(见上模板)
增量掩盖新代码 include_prior=True 按 per-file SHA 判定;变更文件自动失效重读
并发压力 每批 4-6 个并行,其余排队;batch_size 40 控制单组体量
主上下文被大 JSON 撑爆 落盘机制:子代理写临时文件,主代理只读聚合摘要

六、跨轮增量(多轮累积)

  • 每轮报告后 save_coverage_index_tool.code-review-graph/coverage-index.json (相对路径 → per-file SHA)。
  • 下一轮 deep_read_plan_tool(include_prior=True) / coverage_tool(include_prior=True) 自动复用 SHA 未变文件 → 增量任务 = 新增文件 + 变更文件。
  • 多轮后增量归零即实现全库全覆盖,避免每轮从 2-5% 起步。
  • 引擎 B 阶段(compute_coverage 支持 file_read_ranges/file_semantic_unitsgate="both+line"已落地。主代理优先用 coverage_tool(deep_read_files=..., gate="both+line", file_read_ranges=..., file_semantic_units=...) 做三件套门禁(引擎返回 line_coverage_pct/unit_coverage_pct/line_gap_files/unit_gap_files/unit_exempt_files)。 A 阶段聚合脚本 scripts/aggregate_deep_read.py 保留作独立校验兜底(引擎不可用时的替代),两者判定逻辑一致。