SKILL.md
4.18 KB
name: unknown-scope-defect-sweep description: | QA Agent 面对"规模未知"的扫描/审计类任务(没有预先划定范围,比如"找出所有未处理的 Promise""审计所有路由文件的鉴权缺失")时使用:持续搜索、按结构性标识去重、连续两轮 无新发现才停止,避免"扫一遍就当扫完了"或反过来无限扫描下去。 version: 1.0.0 tags:
- qa
- convergence
- sweep metadata: origin: graphlemon-native related: [qa-task-validation, docs/done/validator-loop-until-dry-skill-design.md] platforms: [linux, macos, windows] ---
SKILL:unknown-scope-defect-sweep
适用场景
- 任务描述里没有给出确切的验收对象数量或边界("扫描整个代码库找 X""审计所有 Y"),开始前说不清楚"验收完了应该恰好找到几个"。
- 不适用:验收对象边界清晰(一个 Development Unit、一个已知文件列表)的常规任务——那种场景直接走
qa-task-validation的单轮验收流程,不要为了"用上这个 Skill"强行套上多轮扫描的外壳。
核心循环
- 搜索一轮:用当前已知的搜索策略(grep 模式、目录遍历、依赖图遍历……)找出这一轮能发现的候选项。
- 去重:把这一轮的候选项跟"全部已见过的候选项集合"比对(不是跟"已确认为真缺陷的集合"比对——见下面"去重键"一节,这是本 Skill 最容易踩错的一步)。
- 验证:对这一轮真正新增的候选项,套用
qa-task-validation已有的 PASS/FAIL/INCONCLUSIVE 判定框架逐个判断是不是真缺陷。不接根因归属机制(那是验证失败之后才需要的另一个步骤,不是这里的事)。 - 计数:如果这一轮没有产生任何新增候选项(不管是因为没搜到,还是搜到了但已经在"全部已见过"集合里),连续无新发现轮次 +1;否则清零。
- 停止判定:连续无新发现轮次达到 2(K=2)→ 停止,汇总全部经验证为真的候选项。或者总轮次达到 20(硬上限)→ 强制停止,如实报告"已达硬上限,可能未完全收敛",不能假装已经扫完。
去重键——本 Skill 最容易踩错的一步
去重键必须是候选项的结构性标识(文件路径+行号、路由路径、包名/版本这类能唯一定位这个候选项在系统里的位置),不能用候选项的自然语言描述做键。
为什么这条是硬性规则:同一个真实缺陷,模型两次描述的措辞几乎不会逐字相同("第 42 行缺少空值检查" vs "line 42 doesn't check for null")——如果用描述文本做去重键,同一个候选项会在每一轮都被判定成"新发现",收敛条件永远不会触发,循环会一直跑到硬上限才停,而不是真正找完就停。
同样重要:去重比对的是"全部已见过的候选项",不是"已确认通过验证的候选项"。一个候选项如果在验证阶段被判定为误报(FAIL/不是真缺陷),它依然要留在"已见过"集合里——如果只把"已确认"的存进去重集合,下一轮同一个搜索策略会再次挖出这个已经被否决过的候选项,当成"新发现"重新验证一遍,循环同样永远不收敛。这是 14 步版参考资料点名的"几乎所有人第一次实现都会踩的坑"。
硬上限——防止收敛条件本身失效
20 轮是保守默认值(还没有真实运行数据校准,未来观察真实场景后可以调整)。触达硬上限本身不是失败,而是一个诚实的"未收敛"信号:汇总目前已验证为真的候选项,同时明确报告"扫描在达到硬上限时被强制终止,不保证已覆盖全部范围",不要在报告里暗示扫描是完整的。
自审清单
- [ ] 去重键是结构性标识,不是自然语言描述。
- [ ] 去重集合包含"全部见过的",不是只有"已确认的"。
- [ ] 每个新增候选项都经过 PASS/FAIL/INCONCLUSIVE 判断,不是"出现过就算数"。
- [ ] 连续无新发现轮次的计数逻辑正确(新一轮只要有任何新增候选项就清零,不是永久递增)。
- [ ] 达到硬上限时如实报告"可能未收敛",没有假装扫完。