validator-loop-until-dry-skill-requirements.md 8.43 KB

Validator "未知规模扫描收敛" Skill——需求文档

日期: 2026-08-05 性质: 需求文档(BRD/PRD 层面),不含详细技术设计。回应 docs/todo/graph-engineering-open-items.md 条目 B 的确认结果——"loop-until-dry 落地在 Validator,做成一个 Skill,validator.md 运行时记得调用"。 状态: 草案,待评审。

1. 背景

14 步版对照笔记(docs/reference/Graph Engineering with Claude_ 14-Step roadmap from 0 to graph architect (Full Course).diff-with-graphlemon.md §1 第 11 行、§2)指出:graphlemon 现有的收敛机制只有 Org-level Loop 的固定 3 轮上限(docs/sdd/04-P-流程与状态流转.md 已标注"未来优化候选"),而 14 步版描述的 loop-until-dry(连续 K 轮无新发现才停止,去重要对比"全部见过的"而非"已确认的")没有对应实现。

同一份笔记也指出一个结构性事实:work_graph_orchestrate.py::topological_order 对有环的 graph_manifest 直接报错("graph_manifest has a dependency cycle")——Work Graph 被设计成严格 DAG,图内不支持回路。这意味着 loop-until-dry 不能实现成"graph_manifest 里画一条指回自己的边",那需要改动整个执行模型(run_graph()/topological_order()),代价远大于收益。

关键澄清(本需求的立论基础):loop-until-dry 不需要是 Work Graph 层面的图内回路。它可以是一个 Work Node 内部、单次 agent() 调用会话自己的行为——一次 claude -p 调用本身就是一个多轮工具调用的会话(读文件、搜索、判断、再读文件……),只要 Skill 的提示词要求 Agent"持续搜索直到连续两轮没有新发现才停止、去重比对全部见过而非仅已确认的结果",这个收敛循环完全发生在一次 Work Node 执行内部,graph_manifest 本身仍然是一条无环的边(该节点的输入是任务描述,输出是收敛后的结构化 bug list),不需要改动 topological_order/run_graph 的任何一行代码。这跟"B. loop-until-dry 要不要在 Validator 落地"的确认结果——"做成一个 Skill"——是同一个思路:Skill 是提示词层面的方法论,不是图结构。

2. 目标

  1. 给 Validator 一个新的 Skill,让它在面对"未知规模缺陷扫描"类任务时,能够自主判断收敛(连续 K 轮无新发现才停止),而不是像现在这样只能做"扫一遍就结束"的单轮验证。
  2. 这个 Skill 的去重逻辑必须对比"全部已见过的候选项",而不是只对比"已确认通过的结果"——避免被验证器打回的候选项在下一轮又被当成新发现重新提出,导致循环永远不收敛(14 步版原文点名的"几乎所有人第一次实现都会踩的坑")。
  3. .claude/agents/validator.md(及其 canonical 来源 src/agent_profile.py::FRONTMATTER["validator"])需要引用这个新 Skill,并且 Validator 的人设文档(agents/validator/SOUL.md 迁移版)需要有明确指引:什么场景下应该主动调用这个 Skill,而不是走默认的单轮验证路径。

3. 非目标

  1. 不改 Work Graph 执行模型。不给 graph_manifest/topological_order/run_graph 引入图内回路支持,见第 1 节的关键澄清。
  2. 不改 Org-level Loop 的 3 轮上限。Org-level Loop 管的是"Validator 判定不通过、打回 Planner/Coder、再来一轮"这个更粗粒度的循环,跟这个 Skill 管的"Validator 一次验证任务内部要扫多少轮才算扫完"是两层不同的收敛机制,互不冲突、互不替代。
  3. 不要求这个 Skill 覆盖 Validator 的所有验证场景。大多数验证任务(比如验收一个边界清晰的 Development Unit)本来就是有限规模的,不需要 loop-until-dry;这个 Skill 只服务于"规模未知"这一类场景(比如"扫描整个代码库找所有未处理的 Promise""审计所有路由文件的鉴权缺失"这种没有预先划定范围的任务)。

4. 功能需求

# 需求描述 优先级
FR-1 新增一个 Skill(暂定名 unknown-scope-defect-sweep,具体命名留待设计阶段确定),描述 loop-until-dry 的方法论:持续搜索/扫描 → 每轮结果与"全部已见过的候选项"去重 → 连续 K 轮(默认值留待设计阶段确定,参考 14 步版建议的 K=2)无新发现 → 停止并汇总。 必须
FR-2 Skill 需要明确定义"候选项"的去重键(key)该怎么取——不同任务场景(bug 扫描 vs 路由审计 vs 依赖审计)候选项的自然标识不同,Skill 需要给出通用指导原则,而不是绑定某一种具体场景。 必须
FR-3 Skill 执行过程中每一轮的候选发现,在最终汇总前应当经过验证(复用 Validator 已有的 PASS/FAIL/INCONCLUSIVE 判定框架或 root_cause_trace 机制,具体复用方式留待设计阶段确定)——不能是"只要出现过就算数",避免把误报也计入最终结果。 应该
FR-4 src/agent_profile.py::FRONTMATTER["validator"]["skills"] 需要加入这个新 Skill 的目录名,并且 agents/validator/SOUL.md(canonical 人设源文件)需要新增一段指引:什么信号(比如任务描述里出现"扫描/审计/全部/所有"这类无边界表述)应该触发这个 Skill,而不是走默认单轮验证路径。 必须
FR-5 Skill 需要有一个硬性上限(最大轮次或最大 token/时间预算),防止"连续 K 轮无新发现才停"这个收敛条件本身因为某种原因(比如候选项生成逻辑有 bug,每轮都能生成一个"看起来新"但实际重复的假发现)永远不触发,导致单次 Work Node 执行无限跑下去。 必须

5. 验收标准

  1. 给 Validator 一个人为构造的"扫描规模未知"任务(例如一个测试仓库里散落 5 处同一类缺陷),验证 Validator 使用新 Skill 后能够找全全部 5 处,并在连续两轮无新发现后主动停止,不需要人工告诉它"已经找完了"。
  2. 验证去重逻辑:人为构造一个"候选项会被验证器打回、但下一轮扫描逻辑本身还会再次生成同一个候选项"的场景,确认该候选项不会被无限重复计入"新发现",循环能够正常收敛(不是因为侥幸没再被搜到,而是因为去重键命中了"已见过"记录)。
  3. 验证 FR-5 的硬上限:人为构造一个"永远能生成看似新其实重复"的极端场景,确认 Skill 会在触达硬上限后强制停止并如实报告"可能未收敛",而不是无限执行下去耗尽预算。
  4. .claude/agents/validator.md 部署后(deploy_agent_definitions),能看到新 Skill 出现在 skills: frontmatter 列表里。

6. 约束与假设

  • 复用 Validator 现有的技能目录约定(skills/<name>/SKILL.md,参考 skills/qa-task-validation/SKILL.md 的文件结构),但不复用该文件里遗留的飞书 Base 相关内容(tblnlIVgHNaQXLAL 等)——那是尚未清理的 Hermes profile 遗留细节,新 Skill 要按 graphlemon 当前的实际架构(无飞书 Base 依赖)编写,不能照抄旧格式。
  • 假设这个 Skill 在单次 Work Node 执行内部完成收敛循环(一次 claude -p 调用内的多轮工具使用),不依赖 Work Graph 层面的任何调度改动,因此和「G. Work Graph 节点并行执行」没有直接依赖关系,可以独立排期。

7. 风险

  • 收敛判定本身依赖模型自我报告"这轮有没有新发现",如果模型判断不准确(漏报"这是新发现"或误报"这不是新发现"),收敛条件可能提前/延迟触发。FR-3 的"每轮发现经过验证"部分程度上缓解这个风险,但无法完全消除——这是提示词工程层面的固有局限,不是可以被架构设计完全解决的问题。
  • K 值和硬上限的默认值需要实测校准,不同任务规模下合适的 K 值可能不同,第一版先给一个保守默认值,观察真实运行数据后再调整。

8. 开放问题(留给详细设计阶段回答)

  • [ ] Skill 的具体命名和目录结构。
  • [ ] FR-3"复用已有验证框架"的具体接线方式——是在 Skill 提示词里直接要求"每个候选项过一遍 PASS/FAIL/INCONCLUSIVE 判断",还是调用 root_cause_trace 现成的多视角判断机制?
  • [ ] K 值、硬上限的默认数字。
  • [ ] agents/validator/SOUL.md 里新增指引段落的具体触发条件描述(关键词匹配?任务类型标注?)。